Skip to content

Commit fa8d49a

Browse files
Merge remote-tracking branch 'remotes/from/ce/main'
2 parents 4d62700 + a92bffe commit fa8d49a

File tree

17 files changed

+302
-156
lines changed

17 files changed

+302
-156
lines changed

changelog/_10513.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
```release-note:improvement
2+
ui: Adds license banner indicating when cluster is operating in PKI-only mode and hides client counting dashboards for PKI-only clusters.

ui/app/components/dashboard/overview.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type Args = {
1313
replication: unknown;
1414
secretsEngines: unknown;
1515
vaultConfiguration: unknown;
16-
version: { isEnterprise: boolean };
16+
version: { isEnterprise: boolean; hasPKIOnly: boolean };
1717
};
1818

1919
export default class OverviewComponent extends Component<Args> {
@@ -33,6 +33,9 @@ export default class OverviewComponent extends Component<Args> {
3333
// don't show client count if this isn't an enterprise cluster
3434
if (!version.isEnterprise) return false;
3535

36+
// don't show client count if this is a PKI-only Secrets cluster
37+
if (version.hasPKIOnly) return false;
38+
3639
// HVD clusters
3740
if (namespace.inHvdAdminNamespace) return true;
3841

ui/app/components/license-banners.hbs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<Hds::Alert
88
@type="inline"
99
@color="critical"
10-
@onDismiss={{fn this.dismissBanner "expired"}}
11-
data-test-license-banner-expired
10+
@onDismiss={{fn this.dismissBanner this.banners.EXPIRED}}
11+
data-test-license-banner={{this.banners.EXPIRED}}
1212
as |A|
1313
>
1414
<A.Title>License expired</A.Title>
@@ -17,18 +17,20 @@
1717
{{date-format @expiry "MMM d, yyyy"}}. Add a new license to your configuration and restart Vault.
1818
</A.Description>
1919
<A.Description class="has-top-margin-xs">
20-
<DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license">
21-
Read documentation
22-
<Icon @name="learn-link" />
23-
</DocLink>
20+
<Hds::Link::Standalone
21+
@icon="learn-link"
22+
@iconPosition="trailing"
23+
@href={{doc-link "/vault/tutorials/enterprise/hashicorp-enterprise-license"}}
24+
@text="Read documentation"
25+
/>
2426
</A.Description>
2527
</Hds::Alert>
2628
{{else if (and (lte this.licenseExpiringInDays 30) (not this.warningDismissed))}}
2729
<Hds::Alert
2830
@type="inline"
2931
@color="warning"
30-
@onDismiss={{fn this.dismissBanner "warning"}}
31-
data-test-license-banner-warning
32+
@onDismiss={{fn this.dismissBanner this.banners.WARNING}}
33+
data-test-license-banner={{this.banners.WARNING}}
3234
as |A|
3335
>
3436
<A.Title>Vault license expiring</A.Title>
@@ -46,10 +48,32 @@
4648
}}
4749
</A.Description>
4850
<A.Description class="has-top-margin-xs">
49-
<DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license">
50-
Read documentation
51-
<Icon @name="learn-link" />
52-
</DocLink>
51+
<Hds::Link::Standalone
52+
@icon="learn-link"
53+
@iconPosition="trailing"
54+
@href={{doc-link "/vault/tutorials/enterprise/hashicorp-enterprise-license"}}
55+
@text="Read documentation"
56+
/>
57+
</A.Description>
58+
</Hds::Alert>
59+
{{/if}}
60+
61+
{{#if (and this.isPKIOnly (not this.infoDismissed))}}
62+
<Hds::Alert
63+
@type="inline"
64+
@color="highlight"
65+
@onDismiss={{fn this.dismissBanner this.banners.PKI}}
66+
data-test-license-banner={{this.banners.PKI}}
67+
as |A|
68+
>
69+
<A.Title>Cluster operating in PKI-only mode</A.Title>
70+
<A.Description>
71+
This cluster is operating under PKI-only mode. Other than the built-in Vault PKI engine, all secrets engines are
72+
disabled. The
73+
<Hds::Link::Inline @isHrefExternal={{true}} @href={{doc-link "/vault/api-docs/system/billing/certificates"}}>
74+
number of certificates
75+
</Hds::Link::Inline>
76+
issued is the relevant license utilization metric.
5377
</A.Description>
5478
</Hds::Alert>
5579
{{/if}}

ui/app/components/license-banners.js

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* Copyright IBM Corp. 2016, 2025
3+
* SPDX-License-Identifier: BUSL-1.1
4+
*/
5+
6+
import Component from '@glimmer/component';
7+
import { action } from '@ember/object';
8+
import { tracked } from '@glimmer/tracking';
9+
import { service } from '@ember/service';
10+
import isAfter from 'date-fns/isAfter';
11+
import differenceInDays from 'date-fns/differenceInDays';
12+
import localStorage from 'vault/lib/local-storage';
13+
import timestamp from 'core/utils/timestamp';
14+
import type VersionService from 'vault/services/version';
15+
16+
enum Banners {
17+
EXPIRED = 'expired',
18+
WARNING = 'warning',
19+
PKI = 'pki-only-info',
20+
}
21+
22+
interface Args {
23+
expiry: string;
24+
autoloaded: boolean;
25+
}
26+
27+
/**
28+
* @module LicenseBanners
29+
* LicenseBanners components are used to display Vault-specific license messages
30+
*
31+
* @example
32+
* ```js
33+
* <LicenseBanners @expiry={expiryDate} />
34+
* ```
35+
* @param {string} expiry - RFC3339 date timestamp
36+
*/
37+
38+
export default class LicenseBanners extends Component<Args> {
39+
@service declare readonly version: VersionService;
40+
41+
@tracked warningDismissed = false;
42+
@tracked expiredDismissed = false;
43+
@tracked infoDismissed = false;
44+
45+
banners = Banners;
46+
47+
constructor(owner: unknown, args: Args) {
48+
super(owner, args);
49+
50+
// reset and show a previously dismissed license banner if:
51+
// the version has been updated or the license has been updated (indicated by a change in the expiry date).
52+
const item = localStorage.getItem(this.dismissedBannerKey) ?? []; // returns warning, expired and/or pki-only-info
53+
// older entries will not be an array as it was either "expired" OR "warning"
54+
// with the addition of "pki-only-info", it can hold all values
55+
// this check maintains backwards compatibility with the previous format
56+
const bannerTypes = Array.isArray(item) ? item : [item];
57+
58+
bannerTypes.forEach((type) => {
59+
this.updateDismissType(type);
60+
});
61+
}
62+
63+
get currentVersion() {
64+
return this.version.version;
65+
}
66+
67+
get dismissedBannerKey() {
68+
return `dismiss-license-banner-${this.currentVersion}-${this.args.expiry}`;
69+
}
70+
71+
get licenseExpired() {
72+
if (!this.args.expiry) return false;
73+
return isAfter(timestamp.now(), new Date(this.args.expiry));
74+
}
75+
76+
get licenseExpiringInDays() {
77+
// Anything more than 30 does not render a warning
78+
if (!this.args.expiry) return 99;
79+
return differenceInDays(new Date(this.args.expiry), timestamp.now());
80+
}
81+
82+
get isPKIOnly() {
83+
return this.version.hasPKIOnly;
84+
}
85+
86+
@action
87+
dismissBanner(dismissAction: Banners) {
88+
// if a client's version changed their old localStorage key will still exists.
89+
localStorage.cleanupStorage('dismiss-license-banner', this.dismissedBannerKey);
90+
91+
// updates localStorage and then updates the template by calling updateDismissType
92+
const item = localStorage.getItem(this.dismissedBannerKey) ?? [];
93+
// older entries will not be an array as it was either "expired" OR "warning"
94+
// with the addition of "pki-only-info", it can hold all values
95+
// this check maintains backwards compatibility with the previous format
96+
const bannerTypes = Array.isArray(item) ? item : [item];
97+
localStorage.setItem(this.dismissedBannerKey, [...bannerTypes, dismissAction]);
98+
99+
this.updateDismissType(dismissAction);
100+
}
101+
102+
updateDismissType(dismissType?: Banners) {
103+
// updates tracked properties to update template
104+
switch (dismissType) {
105+
case this.banners.WARNING:
106+
this.warningDismissed = true;
107+
break;
108+
case this.banners.EXPIRED:
109+
this.expiredDismissed = true;
110+
break;
111+
case this.banners.PKI:
112+
this.infoDismissed = true;
113+
break;
114+
default:
115+
break;
116+
}
117+
}
118+
}

ui/app/components/license-info.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import Component from '@glimmer/component';
7-
import { allFeatures } from 'vault/helpers/all-features';
7+
import { allFeatures } from 'core/utils/all-features';
88
/**
99
* @module LicenseInfo
1010
*

ui/app/components/sidebar/nav/cluster.hbs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,12 @@
8585
/>
8686
{{/if}}
8787
{{#if
88-
(and (has-permission "clients" routeParams="activity") (not this.cluster.dr.isSecondary) (not this.hasChrootNamespace))
88+
(and
89+
(has-permission "clients" routeParams="activity")
90+
(not this.cluster.dr.isSecondary)
91+
(not this.hasChrootNamespace)
92+
(not this.version.hasPKIOnly)
93+
)
8994
}}
9095
<Nav.Link
9196
@route="vault.cluster.clients"

ui/app/services/version.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export default class VersionService extends Service {
2828
}
2929

3030
/* Features */
31+
get hasPKIOnly() {
32+
return this.features.includes('PKI-only Secrets');
33+
}
34+
3135
get hasPerfReplication() {
3236
return this.features.includes('Performance Replication');
3337
}

ui/app/helpers/all-features.js renamed to ui/lib/core/addon/utils/all-features.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
* SPDX-License-Identifier: BUSL-1.1
44
*/
55

6-
import { helper as buildHelper } from '@ember/component/helper';
7-
86
const ALL_FEATURES = [
97
'HSM',
108
'Performance Replication',
@@ -19,10 +17,9 @@ const ALL_FEATURES = [
1917
'Entropy Augmentation',
2018
'Transform Secrets Engine',
2119
'Secrets Sync',
20+
'PKI-only Secrets',
2221
];
2322

2423
export function allFeatures() {
2524
return ALL_FEATURES;
2625
}
27-
28-
export default buildHelper(allFeatures);

ui/tests/acceptance/enterprise-license-banner-test.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import formatRFC3339 from 'date-fns/formatRFC3339';
1111
import { addDays, subDays } from 'date-fns';
1212
import timestamp from 'core/utils/timestamp';
1313
import { setupMirage } from 'ember-cli-mirage/test-support';
14+
import { GENERAL } from '../helpers/general-selectors';
1415

1516
const generateHealthResponse = (now, state) => {
1617
let expiry;
@@ -58,23 +59,23 @@ module('Acceptance | Enterprise | License banner warnings', function (hooks) {
5859
const healthResp = generateHealthResponse(this.now);
5960
this.server.get('/sys/health', () => healthResp);
6061
await visit('/vault/auth');
61-
assert.dom('[data-test-license-banner-expired]').doesNotExist('expired banner does not show');
62-
assert.dom('[data-test-license-banner-warning]').doesNotExist('warning banner does not show');
62+
assert.dom(GENERAL.licenseBanner('expired')).doesNotExist('expired banner does not show');
63+
assert.dom(GENERAL.licenseBanner('warning')).doesNotExist('warning banner does not show');
6364
this.server.shutdown();
6465
});
6566
test('it shows license banner warning if license expires within 30 days', async function (assert) {
6667
const healthResp = generateHealthResponse(this.now, 'expiring');
6768
this.server.get('/sys/health', () => healthResp);
6869
await visit('/vault/auth');
69-
assert.dom('[data-test-license-banner-warning]').exists('license warning shows');
70+
assert.dom(GENERAL.licenseBanner('warning')).exists('license warning shows');
7071
this.server.shutdown();
7172
});
7273

7374
test('it shows license banner alert if license has already expired', async function (assert) {
7475
const healthResp = generateHealthResponse(this.now, 'expired');
7576
this.server.get('/sys/health', () => healthResp);
7677
await visit('/vault/auth');
77-
assert.dom('[data-test-license-banner-expired]').exists('expired license message shows');
78+
assert.dom(GENERAL.licenseBanner('expired')).exists('expired license message shows');
7879
this.server.shutdown();
7980
});
8081
});

0 commit comments

Comments
 (0)