From 217d43b4c0377f1adde8cb9a878a84ece717097e Mon Sep 17 00:00:00 2001 From: Vault Automation Date: Thu, 7 May 2026 14:01:16 -0600 Subject: [PATCH 1/2] UI: Add primary token input for authed generate operation token in DR (#14508) (#14615) (#14623) * add primary token input for authed generate operation token * update token validation * update tests and cancellation logic * update test selectors * update order of pgp and primary token input * add changelog entry * clean up Co-authored-by: lane-wetmore --- changelog/_14508.txt | 3 + ui/app/adapters/cluster.js | 14 +- ui/app/components/pgp-file.hbs | 16 +- .../addon/components/choose-pgp-key-form.hbs | 16 +- .../addon/components/shamir/dr-token-flow.hbs | 43 ++++- .../addon/components/shamir/dr-token-flow.js | 73 ++++++++- ui/lib/core/addon/components/shamir/flow.js | 10 +- ui/lib/core/addon/components/shamir/form.hbs | 4 +- .../acceptance/reduced-disclosure-test.js | 6 +- ui/tests/acceptance/unseal-test.js | 4 +- .../helpers/components/shamir-selectors.ts | 4 +- .../components/choose-pgp-key-form-test.js | 40 ++--- .../integration/components/pgp-file-test.js | 14 +- .../components/shamir/dr-token-flow-test.js | 155 ++++++++++++------ .../components/shamir/flow-test.js | 16 +- .../components/shamir/form-test.js | 19 ++- 16 files changed, 285 insertions(+), 152 deletions(-) create mode 100644 changelog/_14508.txt diff --git a/changelog/_14508.txt b/changelog/_14508.txt new file mode 100644 index 0000000000..8715010438 --- /dev/null +++ b/changelog/_14508.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Update DR operation token generation to accept a primary root token for authentication. +``` \ No newline at end of file diff --git a/ui/app/adapters/cluster.js b/ui/app/adapters/cluster.js index 8578a1529a..01670f8672 100644 --- a/ui/app/adapters/cluster.js +++ b/ui/app/adapters/cluster.js @@ -193,10 +193,20 @@ export default ApplicationAdapter.extend({ // progress the operation url += 'update'; } - return this.ajax(url, verb, { + + const ajaxOptions = { data, unauthenticated: true, - }); + }; + + // If a token is provided, use it for authentication + if (options?.token) { + ajaxOptions.headers = { + 'X-Vault-Token': options.token, + }; + } + + return this.ajax(url, verb, ajaxOptions); }, replicationAction(action, replicationMode, clusterMode, data) { diff --git a/ui/app/components/pgp-file.hbs b/ui/app/components/pgp-file.hbs index 6d31908a48..550db8c9f4 100644 --- a/ui/app/components/pgp-file.hbs +++ b/ui/app/components/pgp-file.hbs @@ -34,20 +34,10 @@
{{#if this.key.enterAsText}}
- + + {{or this.textareaHelpText "Enter a base64-encoded key"}} +
-

- {{#if this.textareaHelpText}} - {{this.textareaHelpText}} - {{else}} - Enter a base64-encoded key - {{/if}} -

{{else}}
diff --git a/ui/lib/core/addon/components/choose-pgp-key-form.hbs b/ui/lib/core/addon/components/choose-pgp-key-form.hbs index a2daf5de24..c7fd1acc4b 100644 --- a/ui/lib/core/addon/components/choose-pgp-key-form.hbs +++ b/ui/lib/core/addon/components/choose-pgp-key-form.hbs @@ -28,7 +28,7 @@ @color="secondary" @onError={{(fn (set-flash-message "Clipboard copy failed. The Clipboard API requires a secure context." "danger"))}} @isTruncated={{true}} - data-test-pgp-key-copy + data-test-copy-snippet="pgp-key" @container="#shamir-flow-modal" />
@@ -41,7 +41,7 @@ data-test-confirm-pgp-back-button /> - + {{else}} @@ -49,7 +49,7 @@ id="choose-pgp-key" {{on "submit" this.usePgpKey}} aria-label="provide PGP key" - data-test-choose-pgp-key-form="begin" + data-test-dr-token-flow-step="choose-pgp-key" >

@@ -58,14 +58,8 @@

- - + + {{/if}} \ No newline at end of file diff --git a/ui/lib/core/addon/components/shamir/dr-token-flow.hbs b/ui/lib/core/addon/components/shamir/dr-token-flow.hbs index 9386ee63d7..428bae26ad 100644 --- a/ui/lib/core/addon/components/shamir/dr-token-flow.hbs +++ b/ui/lib/core/addon/components/shamir/dr-token-flow.hbs @@ -19,7 +19,7 @@ @textToCopy={{this.encodedToken}} @container="#shamir-flow-modal" @onError={{(fn (set-flash-message "Clipboard copy failed. The Clipboard API requires a secure context." "danger"))}} - data-test-shamir-encoded-token + data-test-copy-snippet="shamir-encoded-token" />
{{#if this.otp}} @@ -93,6 +93,7 @@ secondary Disaster Recovery cluster.

+ {{else if this.generateWithPGP}} +{{else if this.askForPrimaryToken}} + + + + To generate an operation token on this DR secondary, you must provide a root token from the primary cluster. This token + will be used to authenticate the operation token generation request. + + + + Primary cluster root token + + + + {{#if this.savedPgpKey}} + + {{/if}} + + {{else}} {{! Generate token flow not started }}
@@ -135,7 +168,7 @@
- +
@@ -145,6 +178,6 @@ \ No newline at end of file diff --git a/ui/lib/core/addon/components/shamir/dr-token-flow.js b/ui/lib/core/addon/components/shamir/dr-token-flow.js index 7973015818..54e6575fd9 100644 --- a/ui/lib/core/addon/components/shamir/dr-token-flow.js +++ b/ui/lib/core/addon/components/shamir/dr-token-flow.js @@ -23,17 +23,21 @@ export default class ShamirDrTokenFlowComponent extends ShamirFlowComponent { @tracked generateWithPGP = false; // controls which form shows @tracked savedPgpKey = null; @tracked otp = ''; + @tracked askForPrimaryToken = false; // controls whether to show primary token input + @tracked primaryRootToken = null; // stores the primary root token constructor() { super(...arguments); - // Fetch status on init - this.attemptProgress(); + // Don't fetch status on init - we'll check it after the user provides the primary token + // Fetching status here would start an unauthenticated generation attempt } reset() { this.generateWithPGP = false; this.savedPgpKey = null; this.otp = ''; + this.askForPrimaryToken = false; + this.primaryRootToken = null; // tracked items on Shamir/Flow this.attemptResponse = null; this.errors = null; @@ -57,7 +61,7 @@ export default class ShamirDrTokenFlowComponent extends ShamirFlowComponent { } get pgpText() { return { - confirm: `Below is the base-64 encoded PGP Key that will be used to encrypt the generated operation token. Next we'll enter portions of the root key to generate an operation token. Click the "Generate operation token" button to proceed.`, + confirm: `Below is the base-64 encoded PGP Key that will be used to encrypt the generated operation token.`, form: `Choose a PGP Key from your computer or paste the contents of one in the form below. This key will be used to Encrypt the generated operation token.`, }; } @@ -95,20 +99,77 @@ export default class ShamirDrTokenFlowComponent extends ShamirFlowComponent { @action usePgpKey(keyfile) { this.savedPgpKey = keyfile; - this.attemptProgress(this.extractData({ attempt: true })); + // Don't start generation yet - show primary token form first + this.generateWithPGP = false; + this.askForPrimaryToken = true; + } + + @action + onSubmitKey(data) { + // Override parent to pass primaryToken + this.attemptProgress(this.extractData(data), this.primaryRootToken); } @action startGenerate(evt) { evt.preventDefault(); - this.attemptProgress(this.extractData({ attempt: true })); + // Show the primary token input form first + this.askForPrimaryToken = true; + } + + @action + updatePrimaryRootToken(evt) { + this.primaryRootToken = evt.target.value; + } + + @action + async validatePrimaryRootToken() { + if (!this.primaryRootToken) { + this.errors = ['Primary root token is required']; + return; + } + + this.errors = null; + + try { + // First, check status to validate the token without starting a new generation + await this.attemptProgress(undefined, this.primaryRootToken); + + if (!this.started) { + // No generation in progress, so start one + await this.attemptProgress(this.extractData({ attempt: true }), this.primaryRootToken); + + // Check if there were errors from starting generation (e.g., invalid PGP key) + if (this.errors) { + return; + } + } + + // Only hide the primary token form if there were no errors + this.askForPrimaryToken = false; + } catch (e) { + if (e.httpStatus === 403) { + this.errors = ['Invalid primary root token. Please check the token and try again.']; + } else { + this.errors = [e.message || 'An error occurred while validating the token']; + } + } + } + + @action + backToPgpForm() { + // Go back to PGP form and clear the saved PGP key + this.askForPrimaryToken = false; + this.generateWithPGP = true; + this.savedPgpKey = null; + this.errors = null; } @action async onCancelClose() { if (!this.encodedToken && this.started) { const adapter = this.store.adapterFor('cluster'); - await adapter.generateDrOperationToken({}, { cancel: true }); + await adapter.generateDrOperationToken({}, { cancel: true, token: this.primaryRootToken }); } this.reset(); if (this.args.onCancel) { diff --git a/ui/lib/core/addon/components/shamir/flow.js b/ui/lib/core/addon/components/shamir/flow.js index 1367541b8b..d98508ca16 100644 --- a/ui/lib/core/addon/components/shamir/flow.js +++ b/ui/lib/core/addon/components/shamir/flow.js @@ -69,18 +69,24 @@ export default class ShamirFlowComponent extends Component { * 2. Attempt progress. This method assumes the correct data * has already been extracted (use this.extractData to customize) * @param {object} data arbitrary data which will be passed to adapter method + * @param {string} primaryToken optional primary root token for DR secondary operations * @returns Promise which should resolve unless throwing error to parent. */ - async attemptProgress(data) { + async attemptProgress(data, primaryToken) { this.errors = null; const action = this.action; const adapter = this.store.adapterFor('cluster'); const method = adapter[action]; + // Only used for DR token generate const checkStatus = data ? false : true; + const options = { checkStatus }; + if (primaryToken) { + options.token = primaryToken; + } try { - const resp = await method.call(adapter, data, { checkStatus }); + const resp = await method.call(adapter, data, options); this.updateProgress(resp); this.handleComplete(resp); return; diff --git a/ui/lib/core/addon/components/shamir/form.hbs b/ui/lib/core/addon/components/shamir/form.hbs index 4adb1b5091..4eea98fbd1 100644 --- a/ui/lib/core/addon/components/shamir/form.hbs +++ b/ui/lib/core/addon/components/shamir/form.hbs @@ -49,13 +49,13 @@ name="key" @value={{this.key}} autocomplete="off" - data-test-shamir-key-input + data-test-input="shamir-key" />
- +
{{#if this.showProgress}} diff --git a/ui/tests/acceptance/reduced-disclosure-test.js b/ui/tests/acceptance/reduced-disclosure-test.js index c84f88c8bd..6544f606d4 100644 --- a/ui/tests/acceptance/reduced-disclosure-test.js +++ b/ui/tests/acceptance/reduced-disclosure-test.js @@ -101,9 +101,9 @@ module('Acceptance | reduced disclosure test', function (hooks) { // unseal for (const key of unsealKeys) { - await fillIn('[data-test-shamir-key-input]', key); + await fillIn(GENERAL.inputByAttr('shamir-key'), key); - await click('button[type="submit"]'); + await click(GENERAL.submitButton); await pollCluster(this.owner); await settled(); @@ -119,7 +119,7 @@ module('Acceptance | reduced disclosure test', function (hooks) { module('enterprise', function () { test('does not allow access to replication pages', async function (assert) { await login(); - assert.dom('[data-test-sidebar-nav-link="Replication"]').doesNotExist('hides replication nav item'); + assert.dom(GENERAL.navLink('Replication')).doesNotExist('hides replication nav item'); await visit(`/vault/replication/dr`); assert.strictEqual( diff --git a/ui/tests/acceptance/unseal-test.js b/ui/tests/acceptance/unseal-test.js index 17d5661b6c..fa20adcb43 100644 --- a/ui/tests/acceptance/unseal-test.js +++ b/ui/tests/acceptance/unseal-test.js @@ -65,9 +65,9 @@ module('Acceptance | unseal', function (hooks) { // unseal for (const key of unsealKeys) { - await fillIn('[data-test-shamir-key-input]', key); + await fillIn(GENERAL.inputByAttr('shamir-key'), key); - await click('button[type="submit"]'); + await click(GENERAL.submitButton); await pollCluster(this.owner); await settled(); diff --git a/ui/tests/helpers/components/shamir-selectors.ts b/ui/tests/helpers/components/shamir-selectors.ts index a08dad49fe..3209cf7853 100644 --- a/ui/tests/helpers/components/shamir-selectors.ts +++ b/ui/tests/helpers/components/shamir-selectors.ts @@ -4,11 +4,9 @@ */ export const SHAMIR_FORM = { - input: '[data-test-shamir-key-input]', inputLabel: '[data-test-shamir-key-label]', - submitButton: '[data-test-shamir-submit]', + flowStep: (step: string) => `[data-test-dr-token-flow-step="${step}"]`, otpInfo: '[data-test-otp-info]', otpCode: '[data-test-otp]', progress: '.shamir-progress', - error: '[data-test-message-error]', }; diff --git a/ui/tests/integration/components/choose-pgp-key-form-test.js b/ui/tests/integration/components/choose-pgp-key-form-test.js index 47813a1dcc..c3da2520a1 100644 --- a/ui/tests/integration/components/choose-pgp-key-form-test.js +++ b/ui/tests/integration/components/choose-pgp-key-form-test.js @@ -11,14 +11,9 @@ import { hbs } from 'ember-cli-htmlbars'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; const CHOOSE_PGP = { - begin: '[data-test-choose-pgp-key-form="begin"]', + begin: '[data-test-dr-token-flow-step="choose-pgp-key"]', description: '[data-test-choose-pgp-key-description]', - useKeyButton: '[data-test-use-pgp-key-button]', - pgpTextArea: '[data-test-pgp-file-textarea]', confirm: '[data-test-pgp-key-confirm]', - base64Output: '[data-test-pgp-key-copy]', - submit: '[data-test-confirm-pgp-key-submit]', - cancel: '[data-test-use-pgp-key-cancel]', }; module('Integration | Component | choose-pgp-key-form', function (hooks) { setupRenderingTest(hooks); @@ -32,23 +27,22 @@ module('Integration | Component | choose-pgp-key-form', function (hooks) { await render( hbs`` ); - assert.dom(CHOOSE_PGP.begin).exists('PGP key selection form exists'); assert.dom(CHOOSE_PGP.description).hasText('my custom form text', 'uses custom form text'); await click(GENERAL.textToggle); - assert.dom(CHOOSE_PGP.useKeyButton).isDisabled('use pgp button is disabled'); - await fillIn(CHOOSE_PGP.pgpTextArea, 'base64-pgp-key'); - assert.dom(CHOOSE_PGP.useKeyButton).isNotDisabled('use pgp button is no longer disabled'); - await click(CHOOSE_PGP.useKeyButton); + assert.dom(GENERAL.button('use-pgp-key')).isDisabled('use pgp button is disabled'); + await fillIn(GENERAL.textareaByAttr('pgp-key'), 'base64-pgp-key'); + assert.dom(GENERAL.button('use-pgp-key')).isNotDisabled('use pgp button is no longer disabled'); + await click(GENERAL.button('use-pgp-key')); assert .dom(CHOOSE_PGP.confirm) .hasText( 'Below is the base-64 encoded PGP Key that will be used. Click the "Do it" button to proceed.', 'Incorporates button text in confirmation' ); - assert.dom(CHOOSE_PGP.base64Output).hasText('base64-pgp-key', 'Shows PGP key contents'); - assert.dom(CHOOSE_PGP.submit).hasText('Do it', 'uses passed buttonText'); - await click(CHOOSE_PGP.submit); + assert.dom(GENERAL.copySnippet('pgp-key')).hasText('base64-pgp-key', 'Shows PGP key contents'); + assert.dom(GENERAL.submitButton).hasText('Do it', 'uses passed buttonText'); + await click(GENERAL.submitButton); }); test('it calls onSubmit correctly', async function (assert) { @@ -63,19 +57,19 @@ module('Integration | Component | choose-pgp-key-form', function (hooks) { .dom(CHOOSE_PGP.description) .hasText('Choose a PGP Key from your computer or paste the contents of one in the form below.'); await click(GENERAL.textToggle); - assert.dom(CHOOSE_PGP.useKeyButton).isDisabled('use pgp button is disabled'); - await fillIn(CHOOSE_PGP.pgpTextArea, 'base64-pgp-key'); - assert.dom(CHOOSE_PGP.useKeyButton).isNotDisabled('use pgp button is no longer disabled'); - await click(CHOOSE_PGP.useKeyButton); + assert.dom(GENERAL.button('use-pgp-key')).isDisabled('use pgp button is disabled'); + await fillIn(GENERAL.textareaByAttr('pgp-key'), 'base64-pgp-key'); + assert.dom(GENERAL.button('use-pgp-key')).isNotDisabled('use pgp button is no longer disabled'); + await click(GENERAL.button('use-pgp-key')); assert .dom(CHOOSE_PGP.confirm) .hasText( 'Below is the base-64 encoded PGP Key that will be used. Click the "Submit" button to proceed.', 'Confirmation text has buttonText' ); - assert.dom(CHOOSE_PGP.base64Output).hasText('base64-pgp-key', 'Shows PGP key contents'); - assert.dom(CHOOSE_PGP.submit).hasText('Submit', 'uses passed buttonText'); - await click(CHOOSE_PGP.submit); + assert.dom(GENERAL.copySnippet('pgp-key')).hasText('base64-pgp-key', 'Shows PGP key contents'); + assert.dom(GENERAL.submitButton).hasText('Submit', 'uses passed buttonText'); + await click(GENERAL.submitButton); assert.ok(submitSpy.calledOnceWith('base64-pgp-key')); }); @@ -87,8 +81,8 @@ module('Integration | Component | choose-pgp-key-form', function (hooks) { ); await click(GENERAL.textToggle); - await fillIn(CHOOSE_PGP.pgpTextArea, 'base64-pgp-key'); - await click(CHOOSE_PGP.cancel); + await fillIn(GENERAL.textareaByAttr('pgp-key'), 'base64-pgp-key'); + await click(GENERAL.cancelButton); assert.ok(cancelSpy.calledOnce); }); }); diff --git a/ui/tests/integration/components/pgp-file-test.js b/ui/tests/integration/components/pgp-file-test.js index 4ecdf25ccd..247dfae2a5 100644 --- a/ui/tests/integration/components/pgp-file-test.js +++ b/ui/tests/integration/components/pgp-file-test.js @@ -89,13 +89,9 @@ module('Integration | Component | pgp file', function (hooks) { /> `); await click(GENERAL.textToggle); - assert.dom('[data-test-pgp-file-textarea]').exists({ count: 1 }, 'renders the textarea on toggle'); + assert.dom(GENERAL.textareaByAttr('pgp-key')).exists({ count: 1 }, 'renders the textarea on toggle'); - fillIn('[data-test-pgp-file-textarea]', text); - await waitUntil(() => { - return !!this.lastOnChangeCall; - }); - assert.strictEqual(this.lastOnChangeCall[1].value, text, 'the key value is passed to onChange'); + fillIn(GENERAL.textareaByAttr('pgp-key'), text); }); test('toggling back and forth', async function (assert) { @@ -114,9 +110,9 @@ module('Integration | Component | pgp file', function (hooks) { await triggerEvent('[data-test-pgp-file-input]', ...event); await waitUntil(() => find('[data-test-pgp-file-input-label]').innerText === 'file.json'); await click(GENERAL.textToggle); - assert.dom('[data-test-pgp-file-textarea]').exists({ count: 1 }, 'renders the textarea on toggle'); + assert.dom(GENERAL.textareaByAttr('pgp-key')).exists({ count: 1 }, 'renders the textarea on toggle'); assert - .dom('[data-test-pgp-file-textarea]') - .hasText(this.lastOnChangeCall[1].value, 'textarea shows the value of the base64d key'); + .dom(GENERAL.textareaByAttr('pgp-key')) + .hasValue(this.lastOnChangeCall[1].value, 'textarea shows the value of the base64d key'); }); }); diff --git a/ui/tests/integration/components/shamir/dr-token-flow-test.js b/ui/tests/integration/components/shamir/dr-token-flow-test.js index ecc198677d..d6d8ef48a4 100644 --- a/ui/tests/integration/components/shamir/dr-token-flow-test.js +++ b/ui/tests/integration/components/shamir/dr-token-flow-test.js @@ -11,15 +11,16 @@ import { hbs } from 'ember-cli-htmlbars'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { overrideResponse } from 'vault/tests/helpers/stubs'; import { GENERAL } from 'vault/tests/helpers/general-selectors'; +import { SHAMIR_FORM } from 'vault/tests/helpers/components/shamir-selectors'; module('Integration | Component | shamir/dr-token-flow', function (hooks) { setupRenderingTest(hooks); setupMirage(hooks); test('begin to middle flow works', async function (assert) { - assert.expect(15); + assert.expect(16); this.server.get('/sys/replication/dr/secondary/generate-operation-token/attempt', function () { - assert.ok('Check endpoint is queried on init'); + assert.ok('Check endpoint is queried'); return {}; }); this.server.post('/sys/replication/dr/secondary/generate-operation-token/attempt', function (_, req) { @@ -52,40 +53,49 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { complete: false, }; }); + await render(hbs``); - assert.dom('[data-test-dr-token-flow-step="begin"]').exists('First step shows'); - assert.dom('[data-test-use-pgp-key-cta]').hasText('Provide PGP Key'); - assert.dom('[data-test-generate-token-cta]').hasText('Generate operation token'); - - await click('[data-test-generate-token-cta]'); + assert.dom(SHAMIR_FORM.flowStep('begin')).exists('First step shows'); + assert.dom(GENERAL.button('use-pgp-key-cta')).hasText('Provide PGP Key'); + assert.dom(GENERAL.button('generate-token-cta')).hasText('Generate operation token'); + await click(GENERAL.button('generate-token-cta')); assert.ok( - await waitUntil(() => find('[data-test-dr-token-flow-step="shamir"]')), - 'shows shamir step after start' + await waitUntil(() => find(SHAMIR_FORM.flowStep('primary-token'))), + 'shows primary token step after start' + ); + + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + assert.ok( + await waitUntil(() => find(SHAMIR_FORM.flowStep('shamir'))), + 'shows shamir step after primary token input' ); assert - .dom('.shamir-progress') + .dom(SHAMIR_FORM.progress) .hasText('0/3 keys provided', 'progress shows reflecting checkStatus response with defaults'); - assert.dom('[data-test-otp-info]').exists('OTP info banner shows'); - assert.dom('[data-test-otp]').hasText('otp-9876', 'Shows OTP in copy banner'); + assert.dom(SHAMIR_FORM.otpInfo).exists('OTP info banner shows'); + assert.dom(SHAMIR_FORM.otpCode).hasText('otp-9876', 'Shows OTP in copy banner'); // Fill in shamir key and submit - await fillIn('[data-test-shamir-key-input]', 'some-key'); - await click('[data-test-shamir-submit]'); + await fillIn(GENERAL.inputByAttr('shamir-key'), 'some-key'); + await click(GENERAL.submitButton); assert.ok( - await waitUntil(() => find('[data-test-otp-info]')), + await waitUntil(() => find(SHAMIR_FORM.otpInfo)), 'OTP info still banner shows even when attempt response does not include it' ); assert - .dom('[data-test-otp]') + .dom(SHAMIR_FORM.otpCode) .hasText('otp-9876', 'Still shows OTP in copy banner when attempt response does not include it'); - assert.dom('.shamir-progress').hasText('1/3 keys provided', 'progress shows reflecting attempt response'); + assert + .dom(SHAMIR_FORM.progress) + .hasText('1/3 keys provided', 'progress shows reflecting attempt response'); }); test('middle to finish flow works', async function (assert) { - assert.expect(9); + assert.expect(10); this.server.get('/sys/replication/dr/secondary/generate-operation-token/attempt', function () { - assert.ok('Check endpoint is queried on init'); + assert.ok('Check endpoint is queried'); return { started: true, nonce: 'nonce-1234', @@ -116,30 +126,37 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { }; }); await render(hbs``); - + await click(GENERAL.button('generate-token-cta')); assert.ok( - await waitUntil(() => find('[data-test-dr-token-flow-step="shamir"]')), - 'shows shamir step after start' + await waitUntil(() => find(SHAMIR_FORM.flowStep('primary-token'))), + 'shows primary token step after start' + ); + + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + assert.ok( + await waitUntil(() => find(SHAMIR_FORM.flowStep('shamir'))), + 'shows shamir step after primary token input' ); assert - .dom('.shamir-progress') + .dom(SHAMIR_FORM.progress) .hasText('2/3 keys provided', 'progress shows reflecting checkStatus response'); - assert.dom('[data-test-otp-info]').doesNotExist('OTP info banner not shown'); - assert.dom('[data-test-otp]').doesNotExist('otp-9876', 'OTP copy banner not shown'); - await fillIn('[data-test-shamir-key-input]', 'some-key'); - await click('[data-test-shamir-submit]'); + assert.dom(SHAMIR_FORM.otpInfo).doesNotExist('OTP info banner not shown'); + assert.dom(SHAMIR_FORM.otpCode).doesNotExist('otp-9876', 'OTP copy banner not shown'); + await fillIn(GENERAL.inputByAttr('shamir-key'), 'some-key'); + await click(GENERAL.submitButton); assert.ok( - await waitUntil(() => find('[data-test-dr-token-flow-step="show-token"]')), + await waitUntil(() => find(SHAMIR_FORM.flowStep('show-token'))), 'updates to show encoded token on complete' ); assert - .dom('[data-test-shamir-encoded-token]') + .dom(GENERAL.copySnippet('shamir-encoded-token')) .hasText('encoded-token-here', 'shows encoded token from /update response'); }); test('it works correctly when pgp key chosen', async function (assert) { - assert.expect(3); + assert.expect(4); this.server.get('/sys/replication/dr/secondary/generate-operation-token/attempt', function () { return {}; }); @@ -157,20 +174,29 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { } ); await render(hbs``); - await click('[data-test-use-pgp-key-cta]'); - assert.dom('[data-test-choose-pgp-key-form="begin"]').exists('PGP form shows'); + await click(GENERAL.button('use-pgp-key-cta')); + + assert.ok(await waitUntil(() => find(SHAMIR_FORM.flowStep('choose-pgp-key'))), 'PGP form shows'); await click(GENERAL.textToggle); - await fillIn('[data-test-pgp-file-textarea]', 'some-key-here'); - await click('[data-test-use-pgp-key-button]'); - await click('[data-test-confirm-pgp-key-submit]'); + await fillIn(GENERAL.textareaByAttr('pgp-key'), 'some-key-here'); + await click(GENERAL.button('use-pgp-key')); + await click(GENERAL.submitButton); + assert.ok( - await waitUntil(() => find('[data-test-dr-token-flow-step="shamir"]')), + await waitUntil(() => find(SHAMIR_FORM.flowStep('primary-token'))), + 'shows primary token input after start' + ); + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + + assert.ok( + await waitUntil(() => find(SHAMIR_FORM.flowStep('shamir'))), 'Renders shamir step after PGP key chosen' ); }); test('it shows error with pgp key', async function (assert) { - assert.expect(2); + assert.expect(3); this.server.get('/sys/replication/dr/secondary/generate-operation-token/attempt', function () { return {}; }); @@ -178,12 +204,21 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { overrideResponse(400, { errors: ['error parsing PGP key'] }) ); await render(hbs``); - await click('[data-test-use-pgp-key-cta]'); - assert.dom('[data-test-choose-pgp-key-form="begin"]').exists('PGP form shows'); + await click(GENERAL.button('use-pgp-key-cta')); + + assert.ok(await waitUntil(() => find(SHAMIR_FORM.flowStep('choose-pgp-key'))), 'PGP form shows'); await click(GENERAL.textToggle); - await fillIn('[data-test-pgp-file-textarea]', 'some-key-here'); - await click('[data-test-use-pgp-key-button]'); - await click('[data-test-confirm-pgp-key-submit]'); + await fillIn(GENERAL.textareaByAttr('pgp-key'), 'some-key-here'); + await click(GENERAL.button('use-pgp-key')); + await click(GENERAL.submitButton); + + assert.ok( + await waitUntil(() => find(SHAMIR_FORM.flowStep('primary-token'))), + 'shows primary token input after start' + ); + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + await waitFor(GENERAL.messageError); assert.dom(GENERAL.messageError).hasText('Error error parsing PGP key'); }); @@ -199,12 +234,12 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { assert.notOk('delete endpoint should not be queried'); return {}; }); + await render( hbs`` ); - - assert.dom('[data-test-shamir-modal-cancel-button]').hasText('Cancel', 'Close button has correct copy'); - await click('[data-test-shamir-modal-cancel-button]'); + assert.dom(GENERAL.cancelButton).hasText('Cancel', 'Close button has correct copy'); + await click(GENERAL.cancelButton); assert.ok(cancelSpy.calledOnce, 'cancel spy called on click'); }); @@ -229,16 +264,24 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { await render( hbs`` ); - assert.dom('[data-test-shamir-modal-cancel-button]').hasText('Cancel', 'Close button has correct copy'); - assert.ok(await waitUntil(() => find('[data-test-shamir-key-input]')), 'shows shamir key input'); - - await click('[data-test-shamir-modal-cancel-button]'); + await click(GENERAL.button('generate-token-cta')); assert.ok( - await waitUntil(() => find('[data-test-generate-token-cta]')), + await waitUntil(() => find(SHAMIR_FORM.flowStep('primary-token'))), + 'shows primary token step after start' + ); + + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + + assert.dom(GENERAL.cancelButton).hasText('Cancel', 'Close button has correct copy'); + assert.ok(await waitUntil(() => find(GENERAL.inputByAttr('shamir-key'))), 'shows shamir key input'); + + await click(GENERAL.cancelButton); + assert.ok( + await waitUntil(() => find(GENERAL.button('generate-token-cta'))), 'shows generate token button again' ); - assert.dom('[data-test-shamir-key-input]').doesNotExist('Does not render input for shamir key'); }); test('it closes correctly when generation is completed', async function (assert) { @@ -262,9 +305,13 @@ module('Integration | Component | shamir/dr-token-flow', function (hooks) { hbs`` ); - await waitUntil(() => find('[data-test-dr-token-flow-step="show-token"]')); - assert.dom('[data-test-shamir-modal-cancel-button]').hasText('Close', 'Close button has correct copy'); - await click('[data-test-shamir-modal-cancel-button]'); + await click(GENERAL.button('generate-token-cta')); + await fillIn(GENERAL.inputByAttr('primary-token'), 'some-token'); + await click('[data-test-submit-primary-token]'); + + await waitUntil(() => find(SHAMIR_FORM.flowStep('show-token'))); + assert.dom(GENERAL.cancelButton).hasText('Close', 'Close button has correct copy'); + await click(GENERAL.cancelButton); assert.ok(cancelSpy.calledOnce, 'cancel spy called on click'); }); }); diff --git a/ui/tests/integration/components/shamir/flow-test.js b/ui/tests/integration/components/shamir/flow-test.js index 80ce10ab86..65a38b440f 100644 --- a/ui/tests/integration/components/shamir/flow-test.js +++ b/ui/tests/integration/components/shamir/flow-test.js @@ -11,7 +11,7 @@ import { hbs } from 'ember-cli-htmlbars'; import Service from '@ember/service'; import { run } from '@ember/runloop'; import { reject, resolve } from 'rsvp'; -import { SHAMIR_FORM } from 'vault/tests/helpers/components/shamir-selectors'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; const licenseError = { httpStatus: 500, errors: ['failed because licensing is in an invalid state'] }; const response = { @@ -70,8 +70,8 @@ module('Integration | Component | shamir/flow', function (hooks) { @onShamirSuccess={{this.onSuccess}} />`); - await fillIn(SHAMIR_FORM.input, this.keyPart); - await click(SHAMIR_FORM.submitButton); + await fillIn(GENERAL.inputByAttr('shamir-key'), this.keyPart); + await click(GENERAL.submitButton); assert.ok(completeSpy.notCalled, 'onShamirSuccess was not called'); assert.ok(updateSpy.calledOnce, 'updateProgress was called'); @@ -83,8 +83,8 @@ module('Integration | Component | shamir/flow', function (hooks) { this.set('checkComplete', () => true); await settled(); - await fillIn(SHAMIR_FORM.input, this.keyPart); - await click(SHAMIR_FORM.submitButton); + await fillIn(GENERAL.inputByAttr('shamir-key'), this.keyPart); + await click(GENERAL.submitButton); assert.ok(completeSpy.calledOnce, 'onShamirSuccess was called'); assert.ok(updateSpy.calledTwice, 'updateProgress was called again'); @@ -105,9 +105,9 @@ module('Integration | Component | shamir/flow', function (hooks) { @checkComplete={{this.checkComplete}} />`); - await fillIn(SHAMIR_FORM.input, this.keyPart); - await click(SHAMIR_FORM.submitButton); - assert.dom(SHAMIR_FORM.error).exists({ count: 2 }, 'renders errors'); + await fillIn(GENERAL.inputByAttr('shamir-key'), this.keyPart); + await click(GENERAL.submitButton); + assert.dom(GENERAL.messageError).exists({ count: 2 }, 'renders errors'); assert.ok(completeSpy.notCalled, 'checkComplete was not called'); assert.ok(updateSpy.notCalled, 'updateProgress was not called'); }); diff --git a/ui/tests/integration/components/shamir/form-test.js b/ui/tests/integration/components/shamir/form-test.js index fd6b1e7652..f145a11021 100644 --- a/ui/tests/integration/components/shamir/form-test.js +++ b/ui/tests/integration/components/shamir/form-test.js @@ -9,6 +9,7 @@ import { setupRenderingTest } from 'vault/tests/helpers'; import { click, render, settled, typeIn } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; import { SHAMIR_FORM } from 'vault/tests/helpers/components/shamir-selectors'; +import { GENERAL } from 'vault/tests/helpers/general-selectors'; module('Integration | Component | shamir/form', function (hooks) { setupRenderingTest(hooks); @@ -21,19 +22,19 @@ module('Integration | Component | shamir/form', function (hooks) { await render(hbs` `); - assert.dom(SHAMIR_FORM.submitButton).hasText('Submit', 'Submit button has default text'); - await click(SHAMIR_FORM.submitButton); + assert.dom(GENERAL.submitButton).hasText('Submit', 'Submit button has default text'); + await click(GENERAL.submitButton); assert.dom(SHAMIR_FORM.progress).doesNotExist('Hides progress bar if none made'); assert.ok(this.submitSpy.notCalled, 'onSubmit was not called'); - await typeIn(SHAMIR_FORM.input, 'this-is-the-key'); - assert.dom(SHAMIR_FORM.input).hasValue('this-is-the-key', 'input value set'); + await typeIn(GENERAL.inputByAttr('shamir-key'), 'this-is-the-key'); + assert.dom(GENERAL.inputByAttr('shamir-key')).hasValue('this-is-the-key', 'input value set'); assert.dom(SHAMIR_FORM.inputLabel).hasText('Shamir key portion', 'label has default text'); - await click(SHAMIR_FORM.submitButton); + await click(GENERAL.submitButton); assert.ok( this.submitSpy.calledOnceWith({ key: 'this-is-the-key' }), 'onSubmit called with correct params' ); - assert.dom(SHAMIR_FORM.input).hasValue('', 'key value reset after submit'); + assert.dom(GENERAL.inputByAttr('shamir-key')).hasValue('', 'key value reset after submit'); await render(hbs` @@ -42,7 +43,7 @@ module('Integration | Component | shamir/form', function (hooks) { `); assert.dom('[data-test-block-content]').hasText('Hello', 'renders block content'); - assert.dom(SHAMIR_FORM.submitButton).hasText('Do the thing', 'uses passed button text'); + assert.dom(GENERAL.submitButton).hasText('Do the thing', 'uses passed button text'); assert.dom(SHAMIR_FORM.inputLabel).hasText('Unseal key', 'uses passed inputLabel'); assert.dom(SHAMIR_FORM.otpInfo).doesNotExist('no OTP info shown'); assert @@ -77,10 +78,10 @@ module('Integration | Component | shamir/form', function (hooks) { @errors={{this.errors}} /> `); - assert.dom(SHAMIR_FORM.error).exists({ count: 2 }, 'renders errors'); + assert.dom(GENERAL.messageError).exists({ count: 2 }, 'renders errors'); this.set('errors', []); await settled(); - assert.dom(SHAMIR_FORM.error).doesNotExist('errors cleared'); + assert.dom(GENERAL.messageError).doesNotExist('errors cleared'); }); }); From a3e1d00ea8b0afaf149a9caeb3ecb6cf39e0c0c4 Mon Sep 17 00:00:00 2001 From: Vault Automation Date: Thu, 7 May 2026 14:25:17 -0600 Subject: [PATCH 2/2] Backport [VAULT-44588] go: upgrade go-plugin to fix file descriptor leak into release/2.x.x+ent into ce/release/2.x.x * Backport [VAULT-44588] go: upgrade go-plugin to fix file descriptor leak into release/2.x.x+ent * [VAULT-44588] go: upgrade go-plugin to fix file descriptor leak Signed-off-by: Ryan Cragun Co-authored-by: Ryan Cragun --- changelog/_14464.txt | 3 +++ go.mod | 8 +++--- go.sum | 16 ++++++------ sdk/go.mod | 22 ++++++++-------- sdk/go.sum | 61 ++++++++++++++++++++++---------------------- 5 files changed, 56 insertions(+), 54 deletions(-) create mode 100644 changelog/_14464.txt diff --git a/changelog/_14464.txt b/changelog/_14464.txt new file mode 100644 index 0000000000..24fca367cd --- /dev/null +++ b/changelog/_14464.txt @@ -0,0 +1,3 @@ +```release-note:bug +go-plugin: Upgrade go-plugin to fix a bug where file descriptors could be leaked when spawning external plugins +``` diff --git a/go.mod b/go.mod index 15e7a0bc3d..81d4ba3d39 100644 --- a/go.mod +++ b/go.mod @@ -107,7 +107,7 @@ require ( github.com/hashicorp/go-memdb v1.3.5 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-pgmultiauth v1.0.0 - github.com/hashicorp/go-plugin v1.7.0 + github.com/hashicorp/go-plugin v1.8.0 github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/go-rootcerts v1.0.2 @@ -181,7 +181,7 @@ require ( github.com/kr/pretty v0.3.1 github.com/kr/text v0.2.0 github.com/mattn/go-colorable v0.1.14 - github.com/mattn/go-isatty v0.0.21 + github.com/mattn/go-isatty v0.0.22 github.com/michaelklishin/rabbit-hole/v2 v2.12.0 github.com/miekg/dns v1.1.50 github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a @@ -235,7 +235,7 @@ require ( golang.org/x/time v0.15.0 golang.org/x/tools v0.43.0 google.golang.org/api v0.275.0 - google.golang.org/grpc v1.80.0 + google.golang.org/grpc v1.81.0 google.golang.org/protobuf v1.36.11 gopkg.in/ory-am/dockertest.v3 v3.3.4 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 @@ -572,7 +572,7 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto v0.0.0-20260406210006-6f92a3bedf2d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect; indirect\ + google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 // indirect; indirect\ gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 5a690ab0dd..c67f4807b4 100644 --- a/go.sum +++ b/go.sum @@ -753,8 +753,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-pgmultiauth v1.0.0 h1:dJzw5y45y04Z3ThX/0DaNTrOrrt6Fe+jiuJzJ9r2M0g= github.com/hashicorp/go-pgmultiauth v1.0.0/go.mod h1:+wRFKBbDws/LM7hcxuclEUGDzzUgescGbdYo4EceYjc= -github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= -github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= +github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a h1:FmnBDwGwlTgugDGbVxwV8UavqSMACbGrUpfc98yFLR4= github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a/go.mod h1:xbXnmKqX9/+RhPkJ4zrEx4738HacP72aaUPlT2RZ4sU= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= @@ -1066,8 +1066,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= -github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mediocregopher/radix/v4 v4.1.4 h1:Uze6DEbEAvL+VHXUEu/EDBTkUk5CLct5h3nVSGpc6Ts= @@ -1773,8 +1773,8 @@ google.golang.org/genproto v0.0.0-20260406210006-6f92a3bedf2d h1:N1Ec54vZnIPd7Mn google.golang.org/genproto v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:c2hJ1grtnH0xUiEKGDGkjGNTJ1Hy2LrblyKOHF0sqRM= google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d h1:/aDRtSZJjyLQzm75d+a1wOJaqyKBMvIAfeQmoa3ORiI= google.golang.org/genproto/googleapis/api v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:etfGUgejTiadZAUaEP14NP97xi1RGeawqkjDARA/UOs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d h1:wT2n40TBqFY6wiwazVK9/iTWbsQrgk5ZfCSVFLO9LQA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1782,8 +1782,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/sdk/go.mod b/sdk/go.mod index 5246baef5a..62c1d98fac 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -23,7 +23,7 @@ require ( github.com/hashicorp/go-kms-wrapping/v2 v2.0.18 github.com/hashicorp/go-metrics v0.5.4 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-plugin v1.7.0 + github.com/hashicorp/go-plugin v1.8.0 github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 github.com/hashicorp/go-secure-stdlib/cryptoutil v0.1.1 @@ -53,10 +53,10 @@ require ( github.com/stretchr/testify v1.11.1 github.com/tink-crypto/tink-go/v2 v2.2.0 go.uber.org/atomic v1.11.0 - golang.org/x/crypto v0.49.0 - golang.org/x/net v0.52.0 + golang.org/x/crypto v0.50.0 + golang.org/x/net v0.53.0 golang.org/x/text v0.36.0 - google.golang.org/grpc v1.79.3 + google.golang.org/grpc v1.81.0 google.golang.org/protobuf v1.36.11 ) @@ -100,7 +100,7 @@ require ( github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -125,15 +125,15 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect - go.opentelemetry.io/otel v1.42.0 // indirect - go.opentelemetry.io/otel/metric v1.42.0 // indirect - go.opentelemetry.io/otel/trace v1.42.0 // indirect + go.opentelemetry.io/otel v1.43.0 // indirect + go.opentelemetry.io/otel/metric v1.43.0 // indirect + go.opentelemetry.io/otel/trace v1.43.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/term v0.41.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/term v0.42.0 // indirect golang.org/x/time v0.15.0 // indirect google.golang.org/api v0.271.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260330182312-d5a96adf58d8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sdk/go.sum b/sdk/go.sum index a333abf7eb..aa8435150d 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -176,8 +176,8 @@ github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6e github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= -github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs= +github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= @@ -287,8 +287,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microsoft/go-mssqldb v1.9.8 h1:d4IFMvF/o+HdpXUqbBfzHvn/NlFA75YGcfHUUvDFJEM= github.com/microsoft/go-mssqldb v1.9.8/go.mod h1:eGSRSGAW4hKMy5YcAenhCDjIRm2rhqIdmmwgciMzLus= @@ -412,16 +412,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= -go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= -go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= -go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= -go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= -go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= -go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= -go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= -go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= -go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= -go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= +go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= +go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= +go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= +go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= +go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -433,8 +433,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -467,8 +467,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= @@ -512,15 +512,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -530,8 +529,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -558,8 +557,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/api v0.271.0 h1:cIPN4qcUc61jlh7oXu6pwOQqbJW2GqYh5PS6rB2C/JY= google.golang.org/api v0.271.0/go.mod h1:CGT29bhwkbF+i11qkRUJb2KMKqcJ1hdFceEIRd9u64Q= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -569,17 +568,17 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d h1:vsOm753cOAMkt76efriTCDKjpCbK18XGHMJHo0JUKhc= google.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:0oz9d7g9QLSdv9/lgbIjowW1JoxMbxmBVNe8i6tORJI= -google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s= -google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260330182312-d5a96adf58d8 h1:OHkuo1i98/05rzpm9NBbfEtpJH/k3abEgZUKaAuCI7Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260330182312-d5a96adf58d8/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 h1:pfIbyB44sWzHiCpRqIen67ZQnVXSfIxWrqUMk1qwODE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=