From bcf074b499ea003aa067acced6bafb93d9632d3a Mon Sep 17 00:00:00 2001 From: Brian Botha Date: Fri, 30 Aug 2024 13:38:25 +1000 Subject: [PATCH] fix: fixed parsing secret path not parsing the optional value --- src/secrets/CommandList.ts | 2 +- src/utils/parsers.ts | 52 +++++++++++++++++-------------------- src/vaults/CommandCreate.ts | 7 +---- tests/secrets/env.test.ts | 3 +-- tests/utils/utils.ts | 6 ++--- 5 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/secrets/CommandList.ts b/src/secrets/CommandList.ts index 561dc360..ba88511d 100644 --- a/src/secrets/CommandList.ts +++ b/src/secrets/CommandList.ts @@ -14,7 +14,7 @@ class CommandList extends CommandPolykey { this.argument( '', 'Directory to list files from, specified as [:]', - binParsers.parseSecretName, + binParsers.parseSecretPathOptional, ); this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); diff --git a/src/utils/parsers.ts b/src/utils/parsers.ts index 719affa2..b0d026fe 100644 --- a/src/utils/parsers.ts +++ b/src/utils/parsers.ts @@ -8,8 +8,7 @@ import * as gestaltsUtils from 'polykey/dist/gestalts/utils'; import * as networkUtils from 'polykey/dist/network/utils'; import * as nodesUtils from 'polykey/dist/nodes/utils'; -const vaultNameRegex = /^[\w.-]+$/; -const secretPathNameRegex = /^([\w-]+)(?::([^\0\\=]+))?$/; +const secretPathRegex = /^([\w-]+)(?::([^\0\\=]+))?$/; const secretPathValueRegex = /^([a-zA-Z_][\w]+)?$/; const environmentVariableRegex = /^([a-zA-Z_]+[a-zA-Z0-9_]*)?$/; @@ -66,47 +65,44 @@ function parseCoreCount(v: string): number | undefined { } } -function parseVaultName(vaultName: string): string { - // E.g. If 'vault1, 'vault1' is returned - // If 'vault1:a/b/c', an error is thrown - if (!vaultNameRegex.test(vaultName)) { - throw new commander.InvalidArgumentError( - `${vaultName} is not of the format `, - ); - } - // Returns match[1], or the parsed vaultName - return vaultName.match(secretPathNameRegex)![1]; -} - -function parseSecretName(secretPath: string): [string, string?] { +function parseSecretPathOptional( + secretPath: string, +): [string, string?, string?] { // E.g. If 'vault1:a/b/c', ['vault1', 'a/b/c'] is returned // If 'vault1', ['vault1, undefined] is returned - if (!secretPathNameRegex.test(secretPath)) { + // splits out everything after an `=` separator + const lastEqualIndex = secretPath.lastIndexOf('='); + const splitSecretPath = + lastEqualIndex === -1 + ? secretPath + : secretPath.substring(0, lastEqualIndex); + const value = + lastEqualIndex === -1 + ? undefined + : secretPath.substring(lastEqualIndex + 1); + if (!secretPathRegex.test(splitSecretPath)) { throw new commander.InvalidArgumentError( - `${secretPath} is not of the format [:]`, + `${secretPath} is not of the format [:][=]`, ); } - // Returns [vaultName, secretName?] - const match = secretPath.match(secretPathNameRegex)!; - return [match[1], match[2] || undefined]; + const [, vaultName, directoryPath] = splitSecretPath.match(secretPathRegex)!; + return [vaultName, directoryPath, value]; } function parseSecretPath(secretPath: string): [string, string, string?] { // E.g. If 'vault1:a/b/c', ['vault1', 'a/b/c'] is returned // If 'vault1', an error is thrown - const [vaultName, secretName] = parseSecretName(secretPath); + const [vaultName, secretName, value] = parseSecretPathOptional(secretPath); if (secretName === undefined) { throw new commander.InvalidArgumentError( - `${secretPath} is not of the format :`, + `${secretPath} is not of the format :[=]`, ); } - return [vaultName, secretName]; + return [vaultName, secretName, value]; } function parseSecretPathValue(secretPath: string): [string, string, string?] { - const [vaultName, directoryPath] = parseSecretPath(secretPath); - const lastEqualIndex = secretPath.lastIndexOf('='); - const value = lastEqualIndex === -1 ? '' : secretPath.substring(lastEqualIndex + 1); + const [vaultName, directoryPath, value] = parseSecretPath(secretPath); if (value != null && !secretPathValueRegex.test(value)) { throw new commander.InvalidArgumentError( `${value} is not a valid value name`, @@ -219,13 +215,13 @@ function parseEnvArgs( } export { + secretPathRegex, secretPathValueRegex, environmentVariableRegex, validateParserToArgParser, validateParserToArgListParser, parseCoreCount, - parseVaultName, - parseSecretName, + parseSecretPathOptional, parseSecretPath, parseSecretPathValue, parseSecretPathEnv, diff --git a/src/vaults/CommandCreate.ts b/src/vaults/CommandCreate.ts index 163b37ac..4624955b 100644 --- a/src/vaults/CommandCreate.ts +++ b/src/vaults/CommandCreate.ts @@ -4,7 +4,6 @@ import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; import * as binOptions from '../utils/options'; import * as binProcessors from '../utils/processors'; -import * as binParsers from '../utils/parsers'; class CommandCreate extends CommandPolykey { constructor(...args: ConstructorParameters) { @@ -12,11 +11,7 @@ class CommandCreate extends CommandPolykey { this.name('create'); this.aliases(['touch']); this.description('Create a new Vault'); - this.argument( - '', - 'Name of the new vault to be created', - binParsers.parseVaultName, - ); + this.argument('', 'Name of the new vault to be created'); this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); this.addOption(binOptions.clientPort); diff --git a/tests/secrets/env.test.ts b/tests/secrets/env.test.ts index af560777..103860c5 100644 --- a/tests/secrets/env.test.ts +++ b/tests/secrets/env.test.ts @@ -764,7 +764,7 @@ describe('commandEnv', () => { const jsonOut = JSON.parse(result.stdout); expect(jsonOut['SECRET']).toBe('this is a secret\nit has multiple lines\n'); }); - test.only.prop([ + test.prop([ testUtils.secretPathEnvArrayArb, fc.string().noShrink(), testUtils.cmdArgsArrayArb, @@ -773,7 +773,6 @@ describe('commandEnv', () => { async (secretPathEnvArray, cmd, cmdArgsArray) => { // If we don't use the optional `--` delimiter then we can't include `:` in vault names fc.pre(!cmd.includes(':')); - let output: | [Array<[string, string, string?]>, Array] | undefined = undefined; diff --git a/tests/utils/utils.ts b/tests/utils/utils.ts index 4599b4f2..a9fa9eb5 100644 --- a/tests/utils/utils.ts +++ b/tests/utils/utils.ts @@ -88,9 +88,9 @@ async function nodesConnect(localNode: PolykeyAgent, remoteNode: PolykeyAgent) { ); } -const secretPathWithoutEnvArb = fc - .stringMatching(binParsers.secretPathRegex) - .noShrink(); +// This regex defines a vault secret path that always includes the secret path +const secretPathRegex = /^([\w-]+)(?::)([^\0\\=]+)$/; +const secretPathWithoutEnvArb = fc.stringMatching(secretPathRegex).noShrink(); const environmentVariableAre = fc .stringMatching(binParsers.environmentVariableRegex) .filter((v) => v.length > 0)