diff --git a/lib/vault/api/kv.rb b/lib/vault/api/kv.rb index c400025c..4fb77440 100644 --- a/lib/vault/api/kv.rb +++ b/lib/vault/api/kv.rb @@ -122,6 +122,32 @@ def write_metadata(path, metadata = {}) true end + # Update the secret at the given path with the given data. Note that the + # data must be a {Hash}! Data will be merged with existing values. + # + # Note: This will raise an error if used on KV Secrets Engine Version 1. + # + # @example + # Vault.kv.write("secret/multiple", password: "secret") #=> # + # + # @param [String] path + # the path to update + # @param [Hash] data + # the data to merge + # + # @return [Secret] + def update(path, data = {}, options = {}) + headers = extract_headers!(options) + headers["Content-Type"] = "application/merge-patch+json" + json = client.patch("/v1/#{mount}/data/#{encode_path(path)}", JSON.fast_generate(:data => data), headers) + if json.nil? + return true + else + return Secret.decode(json) + end + end + + # Delete the secret at the given path. If the secret does not exist, vault # will still return true. # diff --git a/spec/integration/api/kv_spec.rb b/spec/integration/api/kv_spec.rb index 7939801d..60a5617e 100644 --- a/spec/integration/api/kv_spec.rb +++ b/spec/integration/api/kv_spec.rb @@ -118,6 +118,38 @@ module Vault end end + describe "#update" do + it "merges data and returns the secret" do + subject.write("test-update", zip: "zap") + subject.update("test-update", zig: "zag") + result = subject.read("test-update") + expect(result).to be + expect(result.data).to eq(zip: "zap", zig: "zag") + end + + it "raises an error if the path does not exist" do + expect { + subject.update("test-update-non-existent", zig: "zag") + }.to raise_error(Vault::HTTPClientError, /404/) + end + + it "raises an error if the path has been deleted" do + expect { + subject.write("test-update-deleted", zip: "zap") + subject.delete("test-update-deleted") + subject.update("test-update-deleted", zig: "zag") + }.to raise_error(Vault::HTTPClientError, /404/) + end + + it "raises an error if the path has been destroyed" do + expect { + subject.write("test-update-destroyed", zip: "zap") + subject.delete("test-update-destroyed") + subject.update("test-update-destroyed", zig: "zag") + }.to raise_error(Vault::HTTPClientError, /404/) + end + end + describe "#delete" do it "deletes the secret" do subject.write("delete", foo: "bar")