localvault 1.12.1 → 1.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/localvault/cli/help_shell.rb +84 -0
- data/lib/localvault/cli.rb +39 -8
- data/lib/localvault/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6798f21f6875910fa68c5300a929b4c18e757a9c03251cd71d46bb46e6cd85b7
|
|
4
|
+
data.tar.gz: a40a445f7d92baad0645bc9ab2f2a900bda43d09a657e07735c565bb5f705f01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45cf703a841eedc73c9b77ac19a92059075dd914c4c1075ff79beca784b61fce4396ffbf51b206315f55c6179c44270d3238a6174c479bc1a2e9e1e9bf4e34d7
|
|
7
|
+
data.tar.gz: 661933cfaa2a6f1a69a5459f0e87580912178e1faeeff0becf7823e4fbb007fa63fad8cfa2f7a05d363146309e20ef1ad4b316143d94a541ba1efb78ae3aa340
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require "thor"
|
|
2
|
+
|
|
3
|
+
module LocalVault
|
|
4
|
+
class CLI
|
|
5
|
+
# Colors every help surface — the main screen, `help COMMAND`, and
|
|
6
|
+
# subcommand namespaces — by hooking the shell Thor already routes all
|
|
7
|
+
# help output through, rather than colorizing at each call site.
|
|
8
|
+
#
|
|
9
|
+
# Thor disables color itself when stdout is not a TTY, so piped output
|
|
10
|
+
# stays plain.
|
|
11
|
+
class HelpShell < Thor::Shell::Color
|
|
12
|
+
# "Usage:", "Options:", "Description:", "Runtime options:"
|
|
13
|
+
LABEL = /\A([A-Z][A-Za-z ]*:)\s*\z/
|
|
14
|
+
# A leading run of caps: "GETTING STARTED", "NESTED KEY (dot-notation)"
|
|
15
|
+
HEADING = /\A(\s*)([A-Z][A-Z0-9'\/\-]*(?: [A-Z0-9'\/\-]+)*)(?=\z|[\s(:])/
|
|
16
|
+
|
|
17
|
+
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
|
18
|
+
if color.nil? && message.is_a?(String)
|
|
19
|
+
message = message.lines.map { |line| decorate(line.chomp) }.join("\n")
|
|
20
|
+
end
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Thor word-wraps long descriptions, which collapses the alignment of
|
|
25
|
+
# example blocks (`localvault set K V # comment` loses its spacing).
|
|
26
|
+
# Lines flagged with \x05 — Thor's no-wrap marker, which every example in
|
|
27
|
+
# our long_desc blocks already carries — are printed verbatim instead, so
|
|
28
|
+
# examples stay aligned while prose still wraps to the terminal.
|
|
29
|
+
def print_wrapped(message, options = {})
|
|
30
|
+
indent = options[:indent] || 0
|
|
31
|
+
prose = []
|
|
32
|
+
|
|
33
|
+
message.to_s.lines.each do |line|
|
|
34
|
+
line = line.chomp
|
|
35
|
+
if line.lstrip.start_with?("\x05")
|
|
36
|
+
wrap_prose(prose, options)
|
|
37
|
+
stdout.puts("#{" " * indent}#{decorate(line.sub("\x05", ''))}")
|
|
38
|
+
elsif line.strip.empty?
|
|
39
|
+
wrap_prose(prose, options)
|
|
40
|
+
stdout.puts
|
|
41
|
+
else
|
|
42
|
+
prose << line
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
wrap_prose(prose, options)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Option tables: green the flag column ("-v, [--vault=VAULT]").
|
|
50
|
+
def print_table(array, options = {})
|
|
51
|
+
array = array.map do |row|
|
|
52
|
+
first, *rest = row
|
|
53
|
+
first.is_a?(String) && first.strip.start_with?("-") ? [set_color(first, :green), *rest] : row
|
|
54
|
+
end
|
|
55
|
+
super
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# Hand a run of prose lines back to Thor's wrapper, then reset the buffer.
|
|
61
|
+
def wrap_prose(lines, options)
|
|
62
|
+
return if lines.empty?
|
|
63
|
+
text = lines.join("\n")
|
|
64
|
+
lines.clear
|
|
65
|
+
return if text.strip.empty?
|
|
66
|
+
Thor::Shell::Basic.instance_method(:print_wrapped)
|
|
67
|
+
.bind_call(self, text.lines.map { |l| decorate(l.chomp) }.join("\n"), options)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def decorate(line)
|
|
71
|
+
return line unless can_display_colors?
|
|
72
|
+
|
|
73
|
+
if (match = LABEL.match(line))
|
|
74
|
+
return line.sub(match[1], set_color(match[1], :cyan, true))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
match = HEADING.match(line)
|
|
78
|
+
return line unless match && match[2].length >= 4
|
|
79
|
+
|
|
80
|
+
"#{match[1]}#{set_color(match[2], :cyan, true)}#{line[(match[1].length + match[2].length)..]}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/localvault/cli.rb
CHANGED
|
@@ -66,7 +66,9 @@ module LocalVault
|
|
|
66
66
|
|
|
67
67
|
def self.start(given_args = ARGV, config = {})
|
|
68
68
|
require_relative "cli/error_presenter"
|
|
69
|
-
|
|
69
|
+
require_relative "cli/help_shell"
|
|
70
|
+
Thor::Base.shell = HelpShell # subcommand namespaces build their own shells
|
|
71
|
+
config[:shell] ||= HelpShell.new
|
|
70
72
|
result = dispatch(nil, normalize_legacy_group_option(given_args.dup), nil, config)
|
|
71
73
|
result.is_a?(CommandStatus) ? result.code : 0
|
|
72
74
|
rescue Thor::Error => error
|
|
@@ -114,7 +116,7 @@ module LocalVault
|
|
|
114
116
|
# disappearing from help.
|
|
115
117
|
HELP_SECTIONS = [
|
|
116
118
|
["GETTING STARTED", %w[login config init demo]],
|
|
117
|
-
["SECRETS", %w[set get show groups list delete import env exec]],
|
|
119
|
+
["SECRETS", %w[set get show reveal groups list delete import env exec]],
|
|
118
120
|
["VAULT MANAGEMENT", %w[vaults switch rekey unlock lock reset rename copy]],
|
|
119
121
|
["SYNC (requires localvault login)", %w[sync]],
|
|
120
122
|
["TEAM SHARING (requires localvault login)", %w[dashboard verify add remove team]],
|
|
@@ -150,8 +152,6 @@ module LocalVault
|
|
|
150
152
|
rendered = sections.map { |title, names| [title, names.flat_map { |n| help_rows_for(n) }] }
|
|
151
153
|
width = rendered.flat_map { |_, rows| rows.map { |usage, _| usage.length } }.max + 4
|
|
152
154
|
|
|
153
|
-
say_header = ->(text) { shell.say shell.set_color(text, :cyan, true) }
|
|
154
|
-
|
|
155
155
|
shell.say ""
|
|
156
156
|
shell.say shell.set_color("LocalVault", :cyan, true) + " — encrypted local secrets vault with MCP support for AI agents"
|
|
157
157
|
shell.say " https://inventlist.com/tools/localvault"
|
|
@@ -159,22 +159,22 @@ module LocalVault
|
|
|
159
159
|
rendered.each do |title, rows|
|
|
160
160
|
next if rows.empty?
|
|
161
161
|
shell.say ""
|
|
162
|
-
|
|
162
|
+
shell.say title
|
|
163
163
|
rows.each do |usage, desc|
|
|
164
164
|
shell.say " localvault #{shell.set_color(usage.ljust(width), :green)}#{desc}"
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
shell.say ""
|
|
169
|
-
|
|
169
|
+
shell.say("SAFE SECRET INPUT (preferred over passing values as arguments)")
|
|
170
170
|
shell.say " printf '%s' \"$SECRET\" | localvault set KEY --stdin"
|
|
171
171
|
shell.say ""
|
|
172
|
-
|
|
172
|
+
shell.say("PROJECTS (dot-notation groups inside one vault)")
|
|
173
173
|
shell.say " localvault set platepose.API_KEY v Store a key in the 'platepose' group"
|
|
174
174
|
shell.say " Filter any command with -p: show -p platepose, exec -p platepose -- CMD"
|
|
175
175
|
shell.say " Delete a whole group: localvault delete 'platepose.*'"
|
|
176
176
|
shell.say ""
|
|
177
|
-
|
|
177
|
+
shell.say("USING SECRETS WITH ANY CLI")
|
|
178
178
|
shell.say " localvault exec -- inventlist ships list"
|
|
179
179
|
shell.say " localvault exec -- curl -H \"Authorization: Bearer $API_KEY\" ..."
|
|
180
180
|
shell.say ""
|
|
@@ -526,6 +526,29 @@ module LocalVault
|
|
|
526
526
|
abort_with "Wrong passphrase for vault '#{vault_name}'"
|
|
527
527
|
end
|
|
528
528
|
|
|
529
|
+
desc "reveal [GROUP]", "Show secrets with values unmasked (same as `show --reveal`)"
|
|
530
|
+
long_desc <<~DESC
|
|
531
|
+
Show secrets with their values unmasked. Identical to `show --reveal`, and
|
|
532
|
+
it takes the same options — `reveal` is simply the verb most people reach
|
|
533
|
+
for. A bare argument is treated as the group to show.
|
|
534
|
+
|
|
535
|
+
\x05 localvault reveal # every secret, unmasked
|
|
536
|
+
\x05 localvault reveal CLOUDFLARE # one group
|
|
537
|
+
\x05 localvault reveal --group CLOUDFLARE # the same thing
|
|
538
|
+
\x05 localvault reveal -p kuickr -v intellectaco
|
|
539
|
+
|
|
540
|
+
Plaintext output is still gated: it refuses to print values when stdout is
|
|
541
|
+
not a terminal, so a redirect or a pipe can't quietly capture secrets.
|
|
542
|
+
DESC
|
|
543
|
+
method_option :group, aliases: "-g", type: :string, lazy_default: GROUP_ALL_SENTINEL, desc: "Show all groups or one group by name"
|
|
544
|
+
method_option :project, aliases: "-p", type: :string, desc: "Show only this project group"
|
|
545
|
+
def reveal(group = nil)
|
|
546
|
+
merged = options.merge("reveal" => true)
|
|
547
|
+
merged["group"] = group if group && merged["project"].nil?
|
|
548
|
+
self.options = merged
|
|
549
|
+
show
|
|
550
|
+
end
|
|
551
|
+
|
|
529
552
|
desc "show", "Display secrets in a formatted table (masked by default)"
|
|
530
553
|
long_desc <<~DESC
|
|
531
554
|
Show secrets in the current vault. Values are masked by default.
|
|
@@ -785,6 +808,14 @@ module LocalVault
|
|
|
785
808
|
require_relative "cli/guard"
|
|
786
809
|
require_relative "cli/identity_cmd"
|
|
787
810
|
|
|
811
|
+
# Thor 1.5 injects a `tree` command into every class. Inside a namespace it
|
|
812
|
+
# lists under a name that isn't even callable (`identity_command tree`), and
|
|
813
|
+
# at top level it prints a raw class path as the root. Our grouped help
|
|
814
|
+
# covers the same ground properly, so drop it everywhere.
|
|
815
|
+
[self, Guard, Keys, Team, Sync, IdentityCommand].each do |namespace|
|
|
816
|
+
namespace.remove_command(:tree) if namespace.all_commands.key?("tree")
|
|
817
|
+
end
|
|
818
|
+
|
|
788
819
|
register(Guard, "guard", "guard SUBCOMMAND", "Block plaintext secrets in agent tool traffic (Claude Code hooks)")
|
|
789
820
|
register(IdentityCommand, "identity", "identity SUBCOMMAND", "Show or set your local identity (alias, handle, public key)")
|
|
790
821
|
register(Keys, "keys", "keys SUBCOMMAND", "Manage your X25519 keypair for vault sharing")
|
data/lib/localvault/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: localvault
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.12.
|
|
4
|
+
version: 1.12.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nauman Tariq
|
|
@@ -112,6 +112,7 @@ files:
|
|
|
112
112
|
- lib/localvault/cli.rb
|
|
113
113
|
- lib/localvault/cli/error_presenter.rb
|
|
114
114
|
- lib/localvault/cli/guard.rb
|
|
115
|
+
- lib/localvault/cli/help_shell.rb
|
|
115
116
|
- lib/localvault/cli/identity_cmd.rb
|
|
116
117
|
- lib/localvault/cli/keys.rb
|
|
117
118
|
- lib/localvault/cli/sync.rb
|