diff --git a/src/secrets/CommandEnv.ts b/src/secrets/CommandEnv.ts index ce92d766..47abc497 100644 --- a/src/secrets/CommandEnv.ts +++ b/src/secrets/CommandEnv.ts @@ -1,4 +1,5 @@ import type PolykeyClient from 'polykey/dist/PolykeyClient'; +import type { ParsedSecretPathValue } from '../types'; import path from 'path'; import os from 'os'; import * as utils from 'polykey/dist/utils'; @@ -29,12 +30,7 @@ class CommandEnv extends CommandPolykey { binParsers.parseEnvArgs, ); this.action( - async ( - args: [Array<[string, string?, string?]>, Array], - options, - ) => { - // Remove the -- from the command arguments - args[1].shift(); + async (args: [Array, Array], options) => { const { default: PolykeyClient } = await import( 'polykey/dist/PolykeyClient' ); diff --git a/src/types.ts b/src/types.ts index b8bccd1f..ab9c8ee7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -61,6 +61,8 @@ type PromiseDeconstructed = { rejectP: (reason?: any) => void; }; +type ParsedSecretPathValue = [string, string?, string?]; + export type { TableRow, TableOptions, @@ -69,4 +71,5 @@ export type { AgentChildProcessInput, AgentChildProcessOutput, PromiseDeconstructed, + ParsedSecretPathValue, }; diff --git a/src/utils/parsers.ts b/src/utils/parsers.ts index eef2dd50..b6fb4398 100644 --- a/src/utils/parsers.ts +++ b/src/utils/parsers.ts @@ -1,5 +1,6 @@ import type { Host, Hostname, Port } from 'polykey/dist/network/types'; import type { SeedNodes } from 'polykey/dist/nodes/types'; +import type { ParsedSecretPathValue } from '../types'; import commander from 'commander'; import * as validationUtils from 'polykey/dist/validation/utils'; import * as validationErrors from 'polykey/dist/validation/errors'; @@ -81,7 +82,7 @@ function parseVaultName(vaultName: string): string { // If 'vault1:', an error is thrown // If 'a/b/c', an error is thrown // Splits out everything after an `=` separator -function parseSecretPath(inputPath: string): [string, string?, string?] { +function parseSecretPath(inputPath: string): ParsedSecretPathValue { // The colon character `:` is prohibited in vaultName, so it's first occurence // means that this is the delimiter between vaultName and secretPath. const colonIndex = inputPath.indexOf(':'); @@ -116,7 +117,7 @@ function parseSecretPath(inputPath: string): [string, string?, string?] { return [vaultName, secretPath, value]; } -function parseSecretPathValue(secretPath: string): [string, string?, string?] { +function parseSecretPathValue(secretPath: string): ParsedSecretPathValue { const [vaultName, directoryPath, value] = parseSecretPath(secretPath); if (value != null && !secretPathValueRegex.test(value)) { throw new commander.InvalidArgumentError( @@ -126,7 +127,7 @@ function parseSecretPathValue(secretPath: string): [string, string?, string?] { return [vaultName, directoryPath, value]; } -function parseSecretPathEnv(secretPath: string): [string, string?, string?] { +function parseSecretPathEnv(secretPath: string): ParsedSecretPathValue { const [vaultName, directoryPath, value] = parseSecretPath(secretPath); if (value != null && !environmentVariableRegex.test(value)) { throw new commander.InvalidArgumentError( @@ -202,30 +203,29 @@ const parseSeedNodes: (data: string) => [SeedNodes, boolean] = */ function parseEnvArgs( value: string, - prev: [Array<[string, string?, string?]>, Array] | undefined, -): [Array<[string, string?, string?]>, Array] { - const current: [Array<[string, string?, string?]>, Array] = prev ?? [ - [], - [], - ]; - if (current[1].length === 0) { + prev: [Array, Array, boolean] | undefined, +): [Array, Array, boolean] { + const current: [Array, Array, boolean] = + prev ?? [[], [], false]; + const [secretsList, commandList, parsingCommandCurrent] = current; + let parsingCommand = parsingCommandCurrent; + if (!parsingCommand) { // Parse a secret path if (value !== '--') { - current[0].push(parseSecretPathEnv(value)); + secretsList.push(parseSecretPathEnv(value)); } else { - current[1].push(value); - return current; + parsingCommand = true; } } else { // Otherwise we just have the cmd args - current[1].push(value); + commandList.push(value); } if (current[0].length === 0 && current[1].length > 0) { throw new commander.InvalidArgumentError( 'You must provide at least 1 secret path', ); } - return current; + return [secretsList, commandList, parsingCommand]; } export { diff --git a/tests/secrets/env.test.ts b/tests/secrets/env.test.ts index 1055ed94..ee848d78 100644 --- a/tests/secrets/env.test.ts +++ b/tests/secrets/env.test.ts @@ -1,4 +1,5 @@ import type { VaultName } from 'polykey/dist/vaults/types'; +import type { ParsedSecretPathValue } from '@/types'; import path from 'path'; import fs from 'fs'; import fc from 'fast-check'; @@ -774,7 +775,7 @@ describe('commandEnv', () => { await polykeyAgent.vaultManager.destroyVault(vaultId); }, ); - test.prop([ + test.only.prop([ testUtils.secretPathEnvArrayArb, fc.string().noShrink(), testUtils.cmdArgsArrayArb, @@ -782,8 +783,10 @@ describe('commandEnv', () => { 'parse secrets env arguments', async (secretPathEnvArray, cmd, cmdArgsArray) => { let output: - | [Array<[string, string?, string?]>, Array] + | [Array, Array, boolean] | undefined = undefined; + // By running the parser directly, we are bypassing commander, so it works + // with a single -- const args: Array = [ ...secretPathEnvArray, '--', @@ -798,7 +801,7 @@ describe('commandEnv', () => { return binParsers.parseSecretPath(v); }); expect(parsedEnvs).toMatchObject(expectedSecretPathArray); - expect(parsedArgs).toMatchObject(['--', cmd, ...cmdArgsArray]); + expect(parsedArgs).toMatchObject([cmd, ...cmdArgsArray]); }, ); test('handles no arguments', async () => {