vaultkit 1.0.1 → 1.0.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 +4 -4
- data/lib/vkit/cli/base_cli.rb +91 -0
- data/lib/vkit/cli/commands/grant_revoke_command.rb +39 -0
- data/lib/vkit/cli/commands/init_command.rb +82 -0
- data/lib/vkit/cli/commands/policy_pack_add_command.rb +38 -0
- data/lib/vkit/cli/commands/policy_pack_info_command.rb +47 -0
- data/lib/vkit/cli/commands/policy_pack_list_command.rb +47 -0
- data/lib/vkit/cli/commands/policy_pack_remove_command.rb +36 -0
- data/lib/vkit/cli/commands/policy_pack_upgrade_command.rb +81 -0
- data/lib/vkit/cli/commands/policy_revoke_command.rb +40 -0
- data/lib/vkit/cli/policy_pack/manager.rb +416 -0
- data/lib/vkit/policy/bundle_compiler.rb +18 -0
- data/lib/vkit/policy/packs/ai_safety/metadata.yaml +10 -0
- data/lib/vkit/policy/packs/ai_safety/policies/01_deny_agent_prod_without_clearance.yaml +14 -0
- data/lib/vkit/policy/packs/ai_safety/policies/02_require_approval_for_sensitive_in_prod.yaml +16 -0
- data/lib/vkit/policy/packs/ai_safety/policies/03_mask_sensitive_by_default_for_agents.yaml +15 -0
- data/lib/vkit/policy/packs/financial_compliance/metadata.yaml +10 -0
- data/lib/vkit/policy/packs/financial_compliance/policies/01_require_approval_for_financial_prod.yaml +16 -0
- data/lib/vkit/policy/packs/financial_compliance/policies/02_mask_payment_tokens.yaml +14 -0
- data/lib/vkit/policy/packs/financial_compliance/policies/03_deny_non_admin_access_pci_in_prod.yaml +15 -0
- data/lib/vkit/policy/packs/financial_compliance/policies/04_short_ttl_for_financial_grants.yaml +14 -0
- data/lib/vkit/policy/packs/starter/metadata.yaml +9 -0
- data/lib/vkit/policy/packs/starter/policies/01_deny_sensitive_without_clearance.yaml +15 -0
- data/lib/vkit/policy/packs/starter/policies/02_mask_pii_by_default.yaml +13 -0
- data/lib/vkit/policy/packs/starter/policies/03_require_approval_high_sensitivity.yaml +17 -0
- data/lib/vkit/policy/packs/starter/policies/04_block_cross_region.yaml +14 -0
- data/lib/vkit/policy/packs/starter/policies/05_limit_production_access.yaml +16 -0
- data/lib/vkit/policy/packs/starter/policies/06_default_ttl.yaml +10 -0
- data/lib/vkit/policy/schema/policy_bundle.schema.json +16 -1
- data/lib/vkit/version.rb +1 -1
- metadata +27 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a8fc789ba6238e633e0638eb06e2bae78b32343dbbbee1c7467bae701a2b38d
|
|
4
|
+
data.tar.gz: a43f1ae331cf39178d22a9f44ca423f3c45dfea81d2265905219432a8f9eca01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 109100e282f4c59e53017492db1a440f6c86d3b6045dce06deb32a2a75c57bcfe908acd28fc94f6e8666382a953c54d4e82d528b59792bc72338d78c90ee3a3c
|
|
7
|
+
data.tar.gz: 1945666c96230884896912a8a6d970eabe743fb412894c17251573dd107aa64cb20ea1997e231bb874eb06b4154821b73adec83827cd1cd899138a08ec8c22e3
|
data/lib/vkit/cli/base_cli.rb
CHANGED
|
@@ -36,6 +36,18 @@ module Vkit
|
|
|
36
36
|
Commands::ResetCommand.new.call
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
desc "init", "Initialize a new VaultKit project"
|
|
40
|
+
option :dir, type: :string, default: ".", desc: "Target directory"
|
|
41
|
+
option :with, type: :string, desc: "Comma-separated policy packs to install (e.g. starter,ai_safety)"
|
|
42
|
+
def init
|
|
43
|
+
packs = options[:with]&.split(",")&.map(&:strip)
|
|
44
|
+
|
|
45
|
+
Commands::InitCommand.new.call(
|
|
46
|
+
dir: options[:dir],
|
|
47
|
+
packs: packs
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
|
|
39
51
|
# REQUEST
|
|
40
52
|
desc "request", "Send an inline JSON AQL request (use --aql or pipe via STDIN)"
|
|
41
53
|
option :aql, type: :string, desc: "AQL JSON payload (inline)"
|
|
@@ -101,6 +113,18 @@ module Vkit
|
|
|
101
113
|
)
|
|
102
114
|
end
|
|
103
115
|
|
|
116
|
+
desc "grant:revoke", "Revoke a grant"
|
|
117
|
+
option :grant, type: :string, required: true
|
|
118
|
+
option :reason, type: :string
|
|
119
|
+
option :force, type: :boolean, default: false
|
|
120
|
+
define_method("grant:revoke") do
|
|
121
|
+
Commands::GrantRevokeCommand.new.call(
|
|
122
|
+
grant_ref: options[:grant],
|
|
123
|
+
reason: options[:reason],
|
|
124
|
+
force: options[:force]
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
104
128
|
# DATASOURCE
|
|
105
129
|
desc "datasource SUBCOMMAND ...ARGS", "Manage datasources (admin only)"
|
|
106
130
|
subcommand "datasource", Class.new(Thor) {
|
|
@@ -186,6 +210,73 @@ module Vkit
|
|
|
186
210
|
activate: options[:activate]
|
|
187
211
|
)
|
|
188
212
|
end
|
|
213
|
+
|
|
214
|
+
desc "revoke", "Revoke a policy bundle version"
|
|
215
|
+
option :bundle_version, type: :string, required: true
|
|
216
|
+
option :reason, type: :string
|
|
217
|
+
option :force, type: :boolean, default: false
|
|
218
|
+
|
|
219
|
+
def revoke
|
|
220
|
+
Commands::PolicyRevokeCommand.new.call(
|
|
221
|
+
bundle_version: options[:bundle_version],
|
|
222
|
+
reason: options[:reason],
|
|
223
|
+
force: options[:force]
|
|
224
|
+
)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
desc "pack SUBCOMMAND ...ARGS", "Manage policy packs"
|
|
228
|
+
subcommand "pack", Class.new(Thor) {
|
|
229
|
+
|
|
230
|
+
desc "list", "List policy packs"
|
|
231
|
+
option :dir, type: :string, default: "."
|
|
232
|
+
def list
|
|
233
|
+
Commands::PolicyPackListCommand.new.call(
|
|
234
|
+
dir: options[:dir]
|
|
235
|
+
)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
desc "add NAME", "Install a policy pack"
|
|
239
|
+
option :dir, type: :string, default: "."
|
|
240
|
+
option :force, type: :boolean, default: false
|
|
241
|
+
def add(name)
|
|
242
|
+
Commands::PolicyPackAddCommand.new.call(
|
|
243
|
+
pack_name: name,
|
|
244
|
+
dir: options[:dir],
|
|
245
|
+
force: options[:force]
|
|
246
|
+
)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
desc "remove NAME", "Remove an installed policy pack"
|
|
250
|
+
option :dir, type: :string, default: "."
|
|
251
|
+
option :force, type: :boolean, default: false
|
|
252
|
+
def remove(name)
|
|
253
|
+
Commands::PolicyPackRemoveCommand.new.call(
|
|
254
|
+
pack_name: name,
|
|
255
|
+
dir: options[:dir],
|
|
256
|
+
force: options[:force]
|
|
257
|
+
)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
desc "info NAME", "Show information about a policy pack"
|
|
261
|
+
option :dir, type: :string, default: "."
|
|
262
|
+
def info(name)
|
|
263
|
+
Commands::PolicyPackInfoCommand.new.call(
|
|
264
|
+
pack_name: name,
|
|
265
|
+
dir: options[:dir]
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
desc "upgrade [NAME]", "Upgrade installed policy packs (all if NAME omitted)"
|
|
270
|
+
option :dir, type: :string, default: "."
|
|
271
|
+
option :force, type: :boolean, default: false
|
|
272
|
+
def upgrade(name = nil)
|
|
273
|
+
Commands::PolicyPackUpgradeCommand.new.call(
|
|
274
|
+
pack_name: name,
|
|
275
|
+
dir: options[:dir],
|
|
276
|
+
force: options[:force]
|
|
277
|
+
)
|
|
278
|
+
end
|
|
279
|
+
}
|
|
189
280
|
}
|
|
190
281
|
|
|
191
282
|
desc "agents SUBCOMMAND ...ARGS", "Manage agents and automation identities"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vkit
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
class GrantRevokeCommand < BaseCommand
|
|
7
|
+
def call(grant_ref:, reason:, force:)
|
|
8
|
+
with_auth do
|
|
9
|
+
user = credential_store.user
|
|
10
|
+
org = user["organization_slug"]
|
|
11
|
+
|
|
12
|
+
raise "Not authenticated. Please login." if org.nil? || org.empty?
|
|
13
|
+
|
|
14
|
+
unless force
|
|
15
|
+
puts "⚠️ You are about to revoke grant: #{grant_ref}"
|
|
16
|
+
puts " Organization: #{org}"
|
|
17
|
+
puts " Reason: #{reason || 'Grant revoked via CLI'}"
|
|
18
|
+
print "Continue? (y/N): "
|
|
19
|
+
answer = STDIN.gets.strip
|
|
20
|
+
return puts("Aborted.") unless answer.downcase == "y"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
response =
|
|
24
|
+
authenticated_client.post(
|
|
25
|
+
"/api/v1/orgs/#{org}/grants/#{grant_ref}/revoke",
|
|
26
|
+
body: {
|
|
27
|
+
reason: reason
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
puts "✅ Grant revoked"
|
|
32
|
+
puts " Grant: #{grant_ref}"
|
|
33
|
+
puts " Revoked: #{response["revoked_at"]}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require_relative "base_command"
|
|
5
|
+
require_relative "../policy_pack/manager"
|
|
6
|
+
|
|
7
|
+
module Vkit
|
|
8
|
+
module CLI
|
|
9
|
+
module Commands
|
|
10
|
+
class InitCommand < BaseCommand
|
|
11
|
+
def call(dir:, packs:)
|
|
12
|
+
dir = File.expand_path(dir)
|
|
13
|
+
FileUtils.mkdir_p(dir)
|
|
14
|
+
|
|
15
|
+
create_structure(dir)
|
|
16
|
+
|
|
17
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
18
|
+
project_root: dir
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
total_policies = 0
|
|
22
|
+
installed = []
|
|
23
|
+
|
|
24
|
+
# Default secure behavior
|
|
25
|
+
if packs.nil? || packs.empty?
|
|
26
|
+
puts "\nℹ️ No packs specified. Installing 'starter' for secure defaults."
|
|
27
|
+
packs = ["starter"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
packs.each do |pack_name|
|
|
31
|
+
count = manager.install_with_deps!(pack_name)
|
|
32
|
+
total_policies += count
|
|
33
|
+
installed << pack_name
|
|
34
|
+
|
|
35
|
+
metadata = manager.pack_metadata(pack_name)
|
|
36
|
+
puts "✓ Installed #{pack_name} pack (v#{metadata['version']}) - #{count} policies"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "\n✅ VaultKit project initialized"
|
|
40
|
+
puts " Location: #{dir}"
|
|
41
|
+
puts " Packs: #{installed.join(', ')}"
|
|
42
|
+
puts " Policies: #{total_policies} total"
|
|
43
|
+
|
|
44
|
+
puts "\nNext steps:"
|
|
45
|
+
puts " 1. Review policies in config/policies/"
|
|
46
|
+
puts " 2. Run: vkit scan <datasource> --apply"
|
|
47
|
+
puts " 3. Run: vkit policy bundle"
|
|
48
|
+
puts " 4. Run: vkit policy deploy"
|
|
49
|
+
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
puts "❌ Error: #{e.message}"
|
|
52
|
+
exit 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def create_structure(dir)
|
|
58
|
+
FileUtils.mkdir_p(File.join(dir, "config", "policies"))
|
|
59
|
+
FileUtils.mkdir_p(File.join(dir, "datasets"))
|
|
60
|
+
FileUtils.mkdir_p(File.join(dir, "dist"))
|
|
61
|
+
FileUtils.mkdir_p(File.join(dir, ".vkit"))
|
|
62
|
+
|
|
63
|
+
registry_path = File.join(dir, "datasets", "registry.yaml")
|
|
64
|
+
unless File.exist?(registry_path)
|
|
65
|
+
File.write(
|
|
66
|
+
registry_path,
|
|
67
|
+
"# Dataset registry\n# Populate with: vkit scan <datasource> --apply\n"
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
gitignore_path = File.join(dir, ".gitignore")
|
|
72
|
+
unless File.exist?(gitignore_path)
|
|
73
|
+
File.write(
|
|
74
|
+
gitignore_path,
|
|
75
|
+
"dist/\n.vkit/\n"
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_command"
|
|
4
|
+
|
|
5
|
+
module Vkit
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class PolicyPackAddCommand < BaseCommand
|
|
9
|
+
def call(pack_name:, dir:, force: false)
|
|
10
|
+
ensure_project!(dir)
|
|
11
|
+
|
|
12
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
13
|
+
project_root: dir
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
count = manager.install!(pack_name, force: force)
|
|
17
|
+
meta = manager.pack_metadata(pack_name)
|
|
18
|
+
|
|
19
|
+
puts "✅ Installed #{pack_name}"
|
|
20
|
+
puts " Version: v#{meta['version']}"
|
|
21
|
+
puts " Policies: #{count} added"
|
|
22
|
+
puts "\nRun 'vkit policy bundle' to compile."
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
puts "❌ Error: #{e.message}"
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def ensure_project!(dir)
|
|
31
|
+
dir = File.expand_path(dir)
|
|
32
|
+
raise "Directory does not exist: #{dir}" unless Dir.exist?(dir)
|
|
33
|
+
raise "Not a VaultKit project (missing .vkit/)" unless Dir.exist?(File.join(dir, ".vkit"))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_command"
|
|
4
|
+
|
|
5
|
+
module Vkit
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class PolicyPackInfoCommand < BaseCommand
|
|
9
|
+
def call(pack_name:, dir:)
|
|
10
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
11
|
+
project_root: dir
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
meta = manager.pack_metadata(pack_name)
|
|
15
|
+
|
|
16
|
+
puts "\nPolicy Pack: #{meta['name']}"
|
|
17
|
+
puts "Version: v#{meta['version']}"
|
|
18
|
+
puts "Layer: #{meta['layer'] || 'n/a'}"
|
|
19
|
+
|
|
20
|
+
deps = Array(meta["dependencies"])
|
|
21
|
+
puts "Dependencies: #{deps.empty? ? 'none' : deps.join(', ')}"
|
|
22
|
+
|
|
23
|
+
band = meta["priority_band"]
|
|
24
|
+
if band
|
|
25
|
+
puts "Priority Band: #{band['min']} – #{band['max']}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
puts "\nPolicies Included:"
|
|
29
|
+
policies = manager.send(:read_pack!, pack_name).last
|
|
30
|
+
policies.each do |p|
|
|
31
|
+
puts " - #{p['id']}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if manager.installed?(pack_name)
|
|
35
|
+
entry = manager.installed_packs[pack_name]
|
|
36
|
+
puts "\nInstalled: yes (v#{entry['version']})"
|
|
37
|
+
else
|
|
38
|
+
puts "\nInstalled: no"
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
puts "❌ Error: #{e.message}"
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_command"
|
|
4
|
+
|
|
5
|
+
module Vkit
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class PolicyPackListCommand < BaseCommand
|
|
9
|
+
def call(dir:)
|
|
10
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
11
|
+
project_root: dir
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
packs = manager.list_status
|
|
15
|
+
|
|
16
|
+
if packs.empty?
|
|
17
|
+
puts "No policy packs available."
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
puts "Available policy packs:\n\n"
|
|
22
|
+
|
|
23
|
+
packs.each do |p|
|
|
24
|
+
name = p["name"]
|
|
25
|
+
shipped = p["shipped_version"]
|
|
26
|
+
installed = p["installed"]
|
|
27
|
+
installed_version = p["installed_version"]
|
|
28
|
+
drift = p["drift"]
|
|
29
|
+
|
|
30
|
+
if installed
|
|
31
|
+
if drift
|
|
32
|
+
puts "⚠ #{name} (installed v#{installed_version}, available v#{shipped})"
|
|
33
|
+
else
|
|
34
|
+
puts "✓ #{name} v#{installed_version}"
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
puts " #{name} (not installed)"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
puts "❌ Error: #{e.message}"
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_command"
|
|
4
|
+
|
|
5
|
+
module Vkit
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class PolicyPackRemoveCommand < BaseCommand
|
|
9
|
+
def call(pack_name:, dir:, force: false)
|
|
10
|
+
ensure_project!(dir)
|
|
11
|
+
|
|
12
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
13
|
+
project_root: dir
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
removed = manager.remove!(pack_name, force: force)
|
|
17
|
+
|
|
18
|
+
puts "✅ Removed #{pack_name}"
|
|
19
|
+
puts " Files deleted: #{removed}"
|
|
20
|
+
puts "\nRun 'vkit policy bundle' to recompile."
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
puts "❌ Error: #{e.message}"
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def ensure_project!(dir)
|
|
29
|
+
dir = File.expand_path(dir)
|
|
30
|
+
raise "Directory does not exist: #{dir}" unless Dir.exist?(dir)
|
|
31
|
+
raise "Not a VaultKit project (missing .vkit/)" unless Dir.exist?(File.join(dir, ".vkit"))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_command"
|
|
4
|
+
|
|
5
|
+
module Vkit
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
class PolicyPackUpgradeCommand < BaseCommand
|
|
9
|
+
def call(pack_name:, dir:, force: false)
|
|
10
|
+
ensure_project!(dir)
|
|
11
|
+
|
|
12
|
+
manager = Vkit::CLI::PolicyPack::Manager.new(
|
|
13
|
+
project_root: dir
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
results =
|
|
17
|
+
if pack_name
|
|
18
|
+
[upgrade_single(manager, pack_name, force)]
|
|
19
|
+
else
|
|
20
|
+
manager.upgrade_all!(force: force)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
print_summary(results)
|
|
24
|
+
|
|
25
|
+
puts "\nRun 'vkit policy bundle' to recompile."
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
puts "❌ Error: #{e.message}"
|
|
28
|
+
exit 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def upgrade_single(manager, pack, force)
|
|
34
|
+
result = manager.upgrade!(pack, force: force)
|
|
35
|
+
|
|
36
|
+
if result == :up_to_date
|
|
37
|
+
{ name: pack, status: :up_to_date }
|
|
38
|
+
else
|
|
39
|
+
{
|
|
40
|
+
name: pack,
|
|
41
|
+
status: :upgraded,
|
|
42
|
+
old: result[:old_version],
|
|
43
|
+
new: result[:new_version],
|
|
44
|
+
policies: result[:policies]
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
rescue => e
|
|
48
|
+
{ name: pack, status: :failed, error: e.message }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def print_summary(results)
|
|
52
|
+
return if results.empty?
|
|
53
|
+
|
|
54
|
+
puts "\nPolicy Pack Upgrade Summary\n"
|
|
55
|
+
|
|
56
|
+
results.each do |r|
|
|
57
|
+
case r[:status]
|
|
58
|
+
when :up_to_date
|
|
59
|
+
puts "✓ #{r[:name]} is already up to date"
|
|
60
|
+
|
|
61
|
+
when :upgraded
|
|
62
|
+
puts "✅ #{r[:name]}"
|
|
63
|
+
puts " From: v#{r[:old]}"
|
|
64
|
+
puts " To: v#{r[:new]}"
|
|
65
|
+
puts " Policies updated: #{r[:policies]}"
|
|
66
|
+
|
|
67
|
+
when :failed
|
|
68
|
+
puts "❌ #{r[:name]}: #{r[:error]}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def ensure_project!(dir)
|
|
74
|
+
dir = File.expand_path(dir)
|
|
75
|
+
raise "Directory does not exist: #{dir}" unless Dir.exist?(dir)
|
|
76
|
+
raise "Not a VaultKit project (missing .vkit/)" unless Dir.exist?(File.join(dir, ".vkit"))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Vkit
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
class PolicyRevokeCommand < BaseCommand
|
|
7
|
+
def call(bundle_version:, reason:, force:)
|
|
8
|
+
with_auth do
|
|
9
|
+
user = credential_store.user
|
|
10
|
+
org = user["organization_slug"]
|
|
11
|
+
|
|
12
|
+
raise "Not authenticated. Please login." if org.nil? || org.empty?
|
|
13
|
+
|
|
14
|
+
unless force
|
|
15
|
+
puts "⚠️ You are about to revoke policy bundle version: #{bundle_version}"
|
|
16
|
+
puts " Organization: #{org}"
|
|
17
|
+
puts " Reason: #{reason || 'Bundle revoked via CLI'}"
|
|
18
|
+
print "Continue? (y/N): "
|
|
19
|
+
answer = STDIN.gets.strip
|
|
20
|
+
return puts("Aborted.") unless answer.downcase == "y"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
response =
|
|
24
|
+
authenticated_client.post(
|
|
25
|
+
"/api/v1/orgs/#{org}/policy_bundles/#{bundle_version}/revoke",
|
|
26
|
+
body: {
|
|
27
|
+
reason: reason
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
puts "✅ Policy bundle revoked"
|
|
32
|
+
puts " Version: #{response["bundle_version"]}"
|
|
33
|
+
puts " Checksum: #{response["checksum"]}"
|
|
34
|
+
puts " Revoked: #{response["revoked_at"]}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|