Merge remote-tracking branch 'remotes/from/ce/main'
Some checks are pending
build / setup (push) Waiting to run
build / Check ce/* Pull Requests (push) Blocked by required conditions
build / ui (push) Blocked by required conditions
build / artifacts-ce (push) Blocked by required conditions
build / artifacts-ent (push) Blocked by required conditions
build / hcp-setup (push) Waiting to run
build / hcp-image (push) Blocked by required conditions
build / test (push) Blocked by required conditions
build / test-hcp-image (push) Blocked by required conditions
build / completed-successfully (push) Blocked by required conditions
CI / setup (push) Waiting to run
CI / Run Autopilot upgrade tool (push) Blocked by required conditions
CI / Run Go tests (push) Blocked by required conditions
CI / Run Go tests tagged with testonly (push) Blocked by required conditions
CI / Run Go tests with data race detection (push) Blocked by required conditions
CI / Run Go tests with FIPS configuration (push) Blocked by required conditions
CI / Test UI (push) Blocked by required conditions
CI / tests-completed (push) Blocked by required conditions
Run linters / Setup (push) Waiting to run
Run linters / Deprecated functions (push) Blocked by required conditions
Run linters / Code checks (push) Blocked by required conditions
Run linters / Protobuf generate delta (push) Blocked by required conditions
Run linters / Format (push) Blocked by required conditions
Run linters / Semgrep (push) Waiting to run
Check Copywrite Headers / copywrite (push) Waiting to run
Security Scan / scan (push) Waiting to run

This commit is contained in:
hc-github-team-secure-vault-core 2026-05-13 22:24:34 +00:00
commit faa255ff4a
7 changed files with 257 additions and 37 deletions

View file

@ -40,7 +40,7 @@
</Hds::Text::Body>
<Hds::Card::Container @hasBorder={{true}} class="has-top-padding-m has-bottom-padding-m side-padding-24">
{{#if (eq this.creationMethodChoice this.methods.APICLI)}}
<CodeGenerator::AutomationSnippets @customTabs={{this.customTabs}} @onTabChange={{fn (mut this.selectedTabIdx)}} />
<CodeGenerator::AutomationSnippets @customTabs={{this.customTabs}} @onTabChange={{this.onTabChange}} />
{{else}}
<Hds::CodeBlock
@language="hcl"

View file

@ -6,13 +6,14 @@
import { action } from '@ember/object';
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { generateCurlCommand } from 'core/utils/code-generators/api';
import { generateCliWriteCommand } from 'core/utils/code-generators/cli';
import { terraformGenericResourceTemplate } from 'core/utils/code-generators/terraform';
import { CreationMethod } from 'vault/utils/constants/snippet';
import type V2Form from 'vault/forms/v2/v2-form';
import type NamespaceService from 'vault/services/namespace';
import type SnippetService from 'vault/services/snippet';
interface Args {
form: V2Form;
@ -21,12 +22,6 @@ interface Args {
onApply: () => void;
}
export enum CreationMethod {
TERRAFORM = 'Terraform automation',
APICLI = 'API/CLI',
UI = 'Vault UI workflow',
}
interface CreationMethodChoice {
icon: string;
label: CreationMethod;
@ -36,9 +31,7 @@ interface CreationMethodChoice {
export default class FormV2Apply extends Component<Args> {
@service declare readonly namespace: NamespaceService;
@tracked creationMethodChoice = CreationMethod.TERRAFORM;
@tracked selectedTabIdx = 0;
@service declare readonly snippet: SnippetService;
methods = CreationMethod;
@ -64,6 +57,14 @@ export default class FormV2Apply extends Component<Args> {
},
];
get creationMethodChoice() {
return this.snippet.creationMethodChoice;
}
get selectedTabIdx() {
return this.snippet.selectedTabIdx;
}
get requestData() {
const { payload } = this.args.form;
// payload has a top level key -- we need the actual data object for creating the snippets
@ -93,6 +94,11 @@ export default class FormV2Apply extends Component<Args> {
@action
onChange(choice: CreationMethodChoice) {
this.creationMethodChoice = choice.label;
this.snippet.setCreationMethod(choice.label, this.tfSnippet, this.customTabs);
}
@action
onTabChange(idx: number) {
this.snippet.setSelectedTab(idx, this.tfSnippet, this.customTabs);
}
}

View file

@ -8,7 +8,7 @@ import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { SecurityPolicy } from 'vault/components/wizard/namespaces/step-1';
import { CreationMethod } from 'vault/components/wizard/namespaces/step-3';
import { CreationMethod } from 'vault/utils/constants/snippet';
import { WIZARD_ID_MAP } from 'vault/utils/constants/wizard';
import type ApiService from 'vault/services/api';

View file

@ -5,10 +5,11 @@
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { SecurityPolicy } from './step-1';
import type NamespaceService from 'vault/services/namespace';
import type SnippetService from 'vault/services/snippet';
import { CreationMethod } from 'vault/utils/constants/snippet';
import {
generateApiSnippet,
generateCliSnippet,
@ -25,12 +26,6 @@ interface Args {
updateWizardState: (key: string, value: unknown) => void;
}
export enum CreationMethod {
TERRAFORM = 'Terraform automation',
APICLI = 'API/CLI',
UI = 'Vault UI workflow',
}
interface CreationMethodChoice {
icon: string;
label: CreationMethod;
@ -40,15 +35,14 @@ interface CreationMethodChoice {
export default class WizardNamespacesStep3 extends Component<Args> {
@service declare readonly namespace: NamespaceService;
@tracked creationMethodChoice: CreationMethod;
@tracked selectedTabIdx = 0;
@service declare readonly snippet: SnippetService;
methods = CreationMethod;
policy = SecurityPolicy;
constructor(owner: unknown, args: Args) {
super(owner, args);
this.creationMethodChoice = this.args.wizardState.creationMethod || CreationMethod.TERRAFORM;
this.snippet.reset(this.args.wizardState.creationMethod || CreationMethod.TERRAFORM);
}
creationMethodOptions: CreationMethodChoice[] = [
@ -73,6 +67,14 @@ export default class WizardNamespacesStep3 extends Component<Args> {
},
];
get creationMethodChoice() {
return this.snippet.creationMethodChoice;
}
get selectedTabIdx() {
return this.snippet.selectedTabIdx;
}
get tfSnippet() {
const { namespacePaths } = this.args.wizardState;
return generateTerraformSnippet(namespacePaths, this.namespace.path);
@ -96,28 +98,20 @@ export default class WizardNamespacesStep3 extends Component<Args> {
@action
onChange(choice: CreationMethodChoice) {
this.creationMethodChoice = choice.label;
this.snippet.setCreationMethod(choice.label, this.tfSnippet, this.customTabs);
this.args.updateWizardState('creationMethod', choice.label);
// Update the code snippet whenever the creation method changes
this.updateCodeSnippet();
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
}
@action
onTabChange(idx: number) {
this.selectedTabIdx = idx;
// Update the code snippet whenever the tab changes
this.updateCodeSnippet();
this.snippet.setSelectedTab(idx, this.tfSnippet, this.customTabs);
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
}
// Update the wizard state with the current code snippet
@action
updateCodeSnippet() {
if (this.creationMethodChoice === CreationMethod.TERRAFORM) {
this.args.updateWizardState('codeSnippet', this.tfSnippet);
} else if (this.creationMethodChoice === CreationMethod.APICLI) {
const snippet = this.customTabs[this.selectedTabIdx]?.snippet;
this.args.updateWizardState('codeSnippet', snippet);
}
this.snippet.persistSnippet(this.tfSnippet, this.customTabs);
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
}
}

View file

@ -0,0 +1,50 @@
/**
* Copyright IBM Corp. 2016, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { CreationMethod } from 'vault/utils/constants/snippet';
export interface SnippetTab {
key: string;
label: string;
snippet: string;
}
export default class SnippetService extends Service {
@tracked selectedTabIdx = 0;
@tracked creationMethodChoice: CreationMethod = CreationMethod.TERRAFORM;
@tracked codeSnippet: string | null = null;
@action
setCreationMethod(choice: CreationMethod, tfSnippet: string, customTabs: SnippetTab[]) {
this.creationMethodChoice = choice;
this.persistSnippet(tfSnippet, customTabs);
}
@action
setSelectedTab(idx: number, tfSnippet: string, customTabs: SnippetTab[]) {
this.selectedTabIdx = idx;
this.persistSnippet(tfSnippet, customTabs);
}
@action
persistSnippet(tfSnippet: string, customTabs: SnippetTab[]) {
if (this.creationMethodChoice === CreationMethod.TERRAFORM) {
this.codeSnippet = tfSnippet;
} else if (this.creationMethodChoice === CreationMethod.APICLI) {
this.codeSnippet = customTabs[this.selectedTabIdx]?.snippet ?? null;
} else {
this.codeSnippet = null;
}
}
reset(initialChoice: CreationMethod = CreationMethod.TERRAFORM) {
this.selectedTabIdx = 0;
this.creationMethodChoice = initialChoice;
this.codeSnippet = null;
}
}

View file

@ -0,0 +1,10 @@
/**
* Copyright IBM Corp. 2016, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
export enum CreationMethod {
TERRAFORM = 'Terraform automation',
APICLI = 'API/CLI',
UI = 'Vault UI workflow',
}

View file

@ -0,0 +1,160 @@
/**
* Copyright IBM Corp. 2016, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import { CreationMethod } from 'vault/utils/constants/snippet';
const TF_SNIPPET = 'resource "vault_mount" "example" {}';
const API_SNIPPET = 'curl --header "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/test';
const CLI_SNIPPET = 'vault write test/path key=value';
const CUSTOM_TABS = [
{ key: 'api', label: 'API', snippet: API_SNIPPET },
{ key: 'cli', label: 'CLI', snippet: CLI_SNIPPET },
];
module('Unit | Service | snippet', function (hooks) {
setupTest(hooks);
hooks.beforeEach(function () {
this.service = this.owner.lookup('service:snippet');
});
module('default state', function () {
test('selectedTabIdx defaults to 0', function (assert) {
assert.strictEqual(this.service.selectedTabIdx, 0);
});
test('creationMethodChoice defaults to TERRAFORM', function (assert) {
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.TERRAFORM);
});
test('codeSnippet defaults to null', function (assert) {
assert.strictEqual(this.service.codeSnippet, null);
});
});
module('#reset', function () {
test('resets service state to defaults', function (assert) {
this.service.selectedTabIdx = 1;
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.codeSnippet = TF_SNIPPET;
this.service.reset();
assert.strictEqual(this.service.selectedTabIdx, 0);
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.TERRAFORM);
assert.strictEqual(this.service.codeSnippet, null);
});
test('accepts an initial creation method', function (assert) {
this.service.reset(CreationMethod.APICLI);
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.APICLI);
assert.strictEqual(this.service.selectedTabIdx, 0);
assert.strictEqual(this.service.codeSnippet, null);
});
});
module('#persistSnippet', function () {
test('sets codeSnippet to tfSnippet when method is TERRAFORM', function (assert) {
this.service.creationMethodChoice = CreationMethod.TERRAFORM;
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
});
test('sets codeSnippet to the selected tab snippet when method is APICLI', function (assert) {
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.selectedTabIdx = 0;
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, API_SNIPPET);
});
test('sets codeSnippet to the CLI tab when selectedTabIdx is 1', function (assert) {
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.selectedTabIdx = 1;
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, CLI_SNIPPET);
});
test('sets codeSnippet to null when method is UI', function (assert) {
this.service.creationMethodChoice = CreationMethod.UI;
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, null);
});
test('sets codeSnippet to null when APICLI tab index is out of range', function (assert) {
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.selectedTabIdx = 99;
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, null);
});
});
module('#setCreationMethod', function () {
test('updates creationMethodChoice', function (assert) {
this.service.setCreationMethod(CreationMethod.APICLI, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.APICLI);
});
test('persists the correct snippet after changing to TERRAFORM', function (assert) {
this.service.setCreationMethod(CreationMethod.TERRAFORM, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
});
test('persists the correct snippet after changing to APICLI', function (assert) {
this.service.selectedTabIdx = 0;
this.service.setCreationMethod(CreationMethod.APICLI, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, API_SNIPPET);
});
test('clears codeSnippet when changing to UI', function (assert) {
this.service.codeSnippet = TF_SNIPPET;
this.service.setCreationMethod(CreationMethod.UI, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, null);
});
});
module('#setSelectedTab', function () {
test('updates selectedTabIdx', function (assert) {
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.selectedTabIdx, 1);
});
test('persists the snippet for the newly selected tab', function (assert) {
this.service.creationMethodChoice = CreationMethod.APICLI;
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, CLI_SNIPPET);
});
test('persists tfSnippet if method is still TERRAFORM when tab changes', function (assert) {
this.service.creationMethodChoice = CreationMethod.TERRAFORM;
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
});
});
});