localvault 1.9.1 → 1.9.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20aa094af163dfa0173fae2eabfc274da78badf84ebc37366bf85163f7b7f77d
4
- data.tar.gz: f113382f8edb4a630732b56de9abe163470c0c377bbcbf64951fde108f6d5e0b
3
+ metadata.gz: f52091ddaad3306c188919a18acc4cae01aff5d0582e3ca07426b6ab3dede07e
4
+ data.tar.gz: 4db7f05666bbb3644b436561e82bcbd51b2b8402618885469ec0534abed60302
5
5
  SHA512:
6
- metadata.gz: e65ac37ab002da71e42ed5d1e31369dd492982683e2817165060962777e197b8873b6c73c11761d2f7aa829c1c6729f7334691d83d16f0de858c59de2a8abbec
7
- data.tar.gz: 2efaf71acba0f24beaa48313a88d0a9f58058d42f7c80a5ef439af76f29deac6df30435dd74868d04d1bbedf224e1d87499a647e32509cecf0895d696f453934
6
+ metadata.gz: 76a6c6007b74d7287673345f0e11b08cc4dca663381b04e6e23e1917d84c92a45f0f9f809be73d028492617b905a66968b0c98791ab0a2772980b94f0e9bcf58
7
+ data.tar.gz: 10751a27f1d8bdce859045e678af61a968a18fe65679dc015a60056502ede9fb4de414439f234ca550da3721f0bd63aaa3e3b93895676b653036befd29d0a348
data/README.md CHANGED
@@ -88,11 +88,11 @@ localvault exec -- rails server
88
88
  | `init [NAME]` | Create a vault (Argon2id key derivation) |
89
89
  | `set KEY --stdin` | Store a secret from stdin without argv/history exposure |
90
90
  | `set KEY [VALUE]` | Store a secret (positional value kept for compatibility) |
91
- | `set --group GROUP KEY --stdin` | Store a secret in a named group from stdin |
91
+ | `set --group GROUP KEY --stdin` | Store a secret in a named group from stdin (`-g`) |
92
92
  | `get KEY` | Retrieve a secret (raw, pipeable) |
93
93
  | `show` | Display all secrets in a table (masked by default) |
94
- | `show --reveal` | Display with values visible |
95
- | `show --group` | Group by dot-notation prefix (one table per project) |
94
+ | `show --reveal` | Display with values visible (`-r`) |
95
+ | `show --group` | Group by dot-notation prefix, one table per project (`-g`) |
96
96
  | `show --group QUERY` | Show one exact or uniquely matching group |
97
97
  | `groups [QUERY]` | List/search group names and key counts without values |
98
98
  | `list` | List key names only |
@@ -243,7 +243,7 @@ module LocalVault
243
243
  Use `localvault show -p platepose -v vault` to view a single project.
244
244
  Use `localvault import` to bulk-load from a .env, .json, or .yml file.
245
245
  DESC
246
- method_option :group, type: :string, desc: "Store KEY and VALUE inside this named group"
246
+ method_option :group, aliases: "-g", type: :string, desc: "Store KEY and VALUE inside this named group"
247
247
  method_option :stdin, type: :boolean, default: false, desc: "Read VALUE from stdin instead of argv"
248
248
  def set(key, value = nil)
249
249
  validate_secret_value_source!(value)
@@ -526,8 +526,8 @@ module LocalVault
526
526
  \x05 localvault show -p platepose -v intellectaco # one project only
527
527
  \x05 localvault show -p platepose -v intellectaco --reveal
528
528
  DESC
529
- method_option :group, type: :string, lazy_default: GROUP_ALL_SENTINEL, desc: "Show all groups or one group by name"
530
- method_option :reveal, type: :boolean, default: false, desc: "Show full values instead of masking"
529
+ method_option :group, aliases: "-g", type: :string, lazy_default: GROUP_ALL_SENTINEL, desc: "Show all groups or one group by name"
530
+ method_option :reveal, aliases: "-r", type: :boolean, default: false, desc: "Show full values instead of masking"
531
531
  method_option :project, aliases: "-p", type: :string, desc: "Show only this project group"
532
532
  def show
533
533
  vault = open_vault!
@@ -1,4 +1,5 @@
1
1
  require "json"
2
+ require "yaml"
2
3
  require "digest"
3
4
  require_relative "store"
4
5
  require_relative "session_cache"
@@ -15,6 +16,44 @@ module LocalVault
15
16
  # check gets uninstalled.
16
17
  module Guard
17
18
  MIN_VALUE_LENGTH = 8
19
+
20
+ # Keys the operator has explicitly declared non-secret, from
21
+ # ~/.localvault/config.yml:
22
+ #
23
+ # guard_ignore:
24
+ # - CLOUDFLARE_ASSETS.r2_bucket
25
+ #
26
+ # WHY EXPLICIT, AND NOT INFERRED FROM THE KEY NAME.
27
+ # The first attempt exempted keys whose name *looked* public — anything
28
+ # ending in bucket / region / _id — with a veto list of credential-ish
29
+ # words. An audit killed it in one line: a value stored under `AWS.bucket`
30
+ # would be exempt regardless of what it actually contained, so the fix
31
+ # traded a false positive for a false NEGATIVE in a security tool. The veto
32
+ # list was also unbounded (pem, jwk, seed, mnemonic, salt, otp, bearer,
33
+ # sas, …) and every omission is a silent bypass.
34
+ #
35
+ # A key's name cannot describe its value. Only the operator can say "this
36
+ # one is public", so only the operator may — by naming the exact full key,
37
+ # in a file they control, which is greppable and auditable.
38
+ #
39
+ # The problem being solved is still real: a public identifier stored beside
40
+ # real secrets (a bucket name that happens to be a substring of a project
41
+ # path) denies every command mentioning that path, and a guard that cries
42
+ # wolf gets uninstalled, which protects nothing. The answer is an explicit
43
+ # allowlist, not a clever one.
44
+ def self.ignored_keys(config_path = default_config_path)
45
+ return [] unless File.exist?(config_path)
46
+
47
+ raw = YAML.safe_load(File.read(config_path)) || {}
48
+ Array(raw["guard_ignore"]).map(&:to_s)
49
+ rescue StandardError
50
+ [] # an unreadable config must never widen the exemption
51
+ end
52
+
53
+ def self.default_config_path
54
+ File.join(Dir.home, ".localvault", "config.yml")
55
+ end
56
+
18
57
  HOOK_ENTRYPOINT = "localvault guard hook".freeze
19
58
  # The installed command must fail open on machines where the binary is
20
59
  # old, missing, or broken — otherwise every Bash call errors for users
@@ -55,12 +94,17 @@ module LocalVault
55
94
  end
56
95
 
57
96
  # @return [Array<Match>] stored secret values appearing in +text+
58
- def self.scan(text, secrets = unlocked_secrets)
97
+ def self.scan(text, secrets = unlocked_secrets, ignore: ignored_keys)
59
98
  return [] if text.nil? || text.empty?
60
99
 
100
+ ignored = Array(ignore).map(&:to_s)
101
+
61
102
  secrets.filter_map do |entry|
62
103
  value = entry[:value]
63
104
  next if value.nil? || value.length < MIN_VALUE_LENGTH
105
+ # Exact full-key match only. No prefixes, no suffix inference — an
106
+ # operator opting one key out must never silently opt out its siblings.
107
+ next if ignored.include?(entry[:key].to_s)
64
108
  next unless text.include?(value)
65
109
 
66
110
  Match.new(vault: entry[:vault], key: entry[:key], fingerprint: fingerprint(value))
@@ -1,3 +1,3 @@
1
1
  module LocalVault
2
- VERSION = "1.9.1"
2
+ VERSION = "1.9.2"
3
3
  end
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.9.1
4
+ version: 1.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nauman Tariq