diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e9c61d4..6082113 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,4 +33,4 @@ jobs: run: npm ci - name: Publish - run: npm publish --access public + run: npm publish --provenance --access public diff --git a/README.md b/README.md index f51229f..299a047 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,16 @@ vaultClient.read('secret/tst').then(lease => { ```javascript const vaultClient = VaultClient.boot('main', { - api: { url: 'https://vault.example.com:8200/' }, + api: { + url: 'https://vault.example.com:8200/', + namespace: 'some_namespace', // Optional. X-Vault-Namespace header (canonical location; auth.config.namespace is honored as a legacy fallback) + }, auth: { type: 'iam', mount: 'aws', // Optional. Vault AWS auth mount point ("aws" by default) config: { role: 'my_iam_role', iam_server_id_header_value: 'https://vault.example.com:8200/', // Optional. X-Vault-AWS-IAM-Server-ID header - namespace: 'some_namespace', // Optional. X-Vault-Namespace header region: 'eu-central-1', // Optional. AWS STS region (see below) credentials: { // Optional. Resolved from the AWS provider chain when omitted accessKeyId: process.env.AWS_ACCESS_KEY_ID, @@ -136,6 +138,14 @@ const vaultClient = VaultClient.boot('main', { * [.read(path)](#VaultClient+read) ⇒ Promise.<Lease> * [.list(path)](#VaultClient+list) ⇒ Promise.<Lease> * [.write(path, data)](#VaultClient+write) ⇒ Promise.<Object> + * [.delete(path)](#VaultClient+delete) ⇒ Promise.<Object> + * [.update(path, data)](#VaultClient+update) ⇒ Promise.<Object> + * [.request(method, path, [data])](#VaultClient+request) ⇒ Promise.<Object> + * [.deleteVersions(path, versions)](#VaultClient+deleteVersions) ⇒ Promise.<Object> + * [.undeleteVersions(path, versions)](#VaultClient+undeleteVersions) ⇒ Promise.<Object> + * [.destroyVersions(path, versions)](#VaultClient+destroyVersions) ⇒ Promise.<Object> + * [.readMetadata(path)](#VaultClient+readMetadata) ⇒ Promise.<Object> + * [.deleteMetadata(path)](#VaultClient+deleteMetadata) ⇒ Promise.<Object> * [.close()](#VaultClient+close) * _static_ * [.boot(name, [options])](#VaultClient.boot) ⇒ VaultClient @@ -143,6 +153,11 @@ const vaultClient = VaultClient.boot('main', { * [.clear([name])](#VaultClient.clear) * [Lease](#Lease) +**Return contract**: [`read()`](#VaultClient+read) and [`list()`](#VaultClient+list) resolve to a +[`Lease`](#Lease) — use its accessors to extract the secret data. Every other data-plane method +(`write`, `delete`, `update`, `request` and the KV v2 helpers) resolves to the raw parsed Vault +response body, which may be empty/undefined for `204 No Content` responses. + #### new VaultClient(options) @@ -157,12 +172,14 @@ Client constructor function. | [options.api.apiVersion] | String | `v1` | | | [options.api.requestOptions] | Object | | extra options merged into every HTTP request (see [Custom transport](#custom-transport-proxy--self-signed-tls)) | | [options.api.namespace] | String | | Optional. Vault namespace, sent as the `X-Vault-Namespace` header on **every** request — login, token lookup/renewal, and all secret operations — for every auth type. This is the canonical location; `auth.config.namespace` is still honored for backward compatibility. | +| [options.api.kv.autoDetect] | boolean | `false` | auto-detect the KV version of each mount on first use (see [KV v2 & generic backends](#kv-v2--generic-backends)) | +| [options.api.engines] | Object | `{}` | static mount-to-version map, e.g. `{ secret: 2, legacy: 1 }` (see [KV v2 & generic backends](#kv-v2--generic-backends)) | | options.auth | Object | | | | options.auth.type | String | | | | [options.auth.mount] | String | | Vault auth backend mount point; default varies per method (e.g. "aws" for iam, "approle", "token", "kubernetes") | | options.auth.config | Object | | auth configuration variables | | [options.auth.config.namespace] | String | | Optional. Legacy location for the Vault namespace (see `api.namespace`). Sent as the `X-Vault-Namespace` header on **every** request for every auth type. | -| options.logger | Object | `false` | | Logger that supports "error", "info", "warn", "trace", "debug" methods. Uses `console` by default. Pass `false` to disable logging. | +| [options.logger] | Object \| false | | Logger that supports "error", "info", "warn", "trace", "debug" methods. Uses `console` by default. Pass `false` to disable logging. | ##### Custom transport (proxy / self-signed TLS) @@ -197,6 +214,8 @@ env var with no code change. Only disable verification (`new Agent({ connect: { rejectUnauthorized: false } })`) in throwaway/dev setups — it removes MITM protection. + + #### vaultClient.fillNodeConfig() ⇒ Promise Populates Vault's values to NPM "config" module @@ -237,9 +256,131 @@ Resolves to the raw parsed Vault response body, which may be empty/undefined for | Param | Type | Description | | --- | --- | --- | -| path | | path used to write data | +| path | string | path used to write data | | data | object | data to write | + + +#### vaultClient.delete(path) ⇒ Promise.<Object> +Deletes a secret + +On KV v2 mounts this sends `DELETE` to the `data/` path, soft-deleting the latest version. +On KV v1 / non-KV mounts this sends `DELETE` to the raw path. Resolves to the raw parsed +Vault response body, which may be empty/undefined for `204 No Content` responses. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | + + + +#### vaultClient.update(path, data) ⇒ Promise.<Object> +Updates (merge-patches) a KV v2 secret + +Sends `PATCH` with `Content-Type: application/merge-patch+json`, merging `data` into the +existing secret without overwriting keys that are not listed. KV v2 merge-patch operation — +KV v1 mounts do not support `PATCH` and Vault returns `405` there. Resolves to the raw +parsed Vault response body. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | +| data | object | keys to merge into the existing secret | + + + +#### vaultClient.request(method, path, [data]) ⇒ Promise.<Object> +Raw request — escape hatch for any Vault backend + +Sends the literal API path with no KV path rewriting and no response unwrapping, and +resolves to the parsed response body. Use it for non-KV backends (e.g. Transit) or when you +have already constructed the complete Vault API path. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| method | string | HTTP method (e.g. `GET`, `POST`) | +| path | string | literal API path, sent as-is | +| [data] | object | request body | + + + +#### vaultClient.deleteVersions(path, versions) ⇒ Promise.<Object> +Soft-deletes specific versions of a KV v2 secret + +KV v2 only — rejects with `UnsupportedOperationError` on non-v2 mounts. Resolves to the raw +parsed Vault response body. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | +| versions | Array.<number> | version numbers to soft-delete | + + + +#### vaultClient.undeleteVersions(path, versions) ⇒ Promise.<Object> +Undeletes (restores) soft-deleted versions of a KV v2 secret + +KV v2 only — rejects with `UnsupportedOperationError` on non-v2 mounts. Resolves to the raw +parsed Vault response body. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | +| versions | Array.<number> | version numbers to restore | + + + +#### vaultClient.destroyVersions(path, versions) ⇒ Promise.<Object> +Permanently destroys specific versions of a KV v2 secret + +The destroyed version data cannot be recovered. KV v2 only — rejects with +`UnsupportedOperationError` on non-v2 mounts. Resolves to the raw parsed Vault response body. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | +| versions | Array.<number> | version numbers to destroy | + + + +#### vaultClient.readMetadata(path) ⇒ Promise.<Object> +Reads KV v2 metadata for a secret + +Resolves to the metadata document (`current_version`, the `versions` map, timestamps, etc.). +KV v2 only — rejects with `UnsupportedOperationError` on non-v2 mounts. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | + + + +#### vaultClient.deleteMetadata(path) ⇒ Promise.<Object> +Deletes all metadata and version history for a KV v2 secret (permanent) + +KV v2 only — rejects with `UnsupportedOperationError` on non-v2 mounts. Resolves to the raw +parsed Vault response body, which may be empty/undefined for `204 No Content` responses. + +**Kind**: instance method of [VaultClient](#VaultClient) + +| Param | Type | Description | +| --- | --- | --- | +| path | string | path to the secret | + #### vaultClient.close()