Module: Legion::Extensions::Velociraptor::Helpers::Cli
- Included in:
- Client, Runners::Collections, Runners::Hunts, Runners::Query
- Defined in:
- lib/legion/extensions/velociraptor/helpers/cli.rb
Defined Under Namespace
Classes: CommandError
Constant Summary collapse
- ENV_KEY_PATTERN =
/\A[A-Za-z_][A-Za-z0-9_]*\z/- ID_PATTERN =
/\A[A-Za-z]\.[A-Za-z0-9_-]+\z/- ARTIFACT_PATTERN =
%r{\A[A-Za-z][A-Za-z0-9_.-]*(/[A-Za-z][A-Za-z0-9_.-]*)?\z}
Instance Method Summary collapse
- #dict_from_env_keys(env) ⇒ Object
- #normalize_env(env) ⇒ Object
- #parse_output(stdout, format) ⇒ Object
- #run_command(command, timeout: nil) ⇒ Object
- #run_vql(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil, timeout: nil) ⇒ Object
- #validate_artifact!(value) ⇒ Object
- #validate_id!(value, label) ⇒ Object
- #velociraptor_query_command(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil) ⇒ Object
- #vql_list(values) ⇒ Object
- #vql_string(value) ⇒ Object
Instance Method Details
#dict_from_env_keys(env) ⇒ Object
112 113 114 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 112 def dict_from_env_keys(env) normalize_env(env).keys.map { |key| "#{key}=#{key}" }.join(', ').then { |items| "dict(#{items})" } end |
#normalize_env(env) ⇒ Object
103 104 105 106 107 108 109 110 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 103 def normalize_env(env) env.to_h.each_with_object({}) do |(key, value), normalized| name = key.to_s raise ArgumentError, "invalid VQL env key: #{name}" unless name.match?(ENV_KEY_PATTERN) normalized[name] = value.to_s end end |
#parse_output(stdout, format) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 67 def parse_output(stdout, format) case format.to_sym when :jsonl stdout.to_s.each_line.filter_map do |line| next if line.strip.empty? stringify_keys(::JSON.parse(line)) end when :json parsed = stringify_keys(::JSON.parse(stdout.to_s)) parsed.is_a?(Array) ? parsed : [parsed] else stdout.to_s end end |
#run_command(command, timeout: nil) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 49 def run_command(command, timeout: nil) stdout, stderr, status = capture(command, timeout: timeout) unless status.success? raise CommandError.new( "velociraptor command failed with exit #{status.exitstatus}", exit_status: status.exitstatus, stderr: stderr, stdout: stdout ) end { success: true, stdout: stdout, stderr: stderr } rescue Errno::ENOENT => e raise CommandError, e. rescue Timeout::Error => e raise CommandError, "velociraptor command timed out: #{e.}" end |
#run_vql(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil, timeout: nil) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 27 def run_vql(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil, timeout: nil, **) normalized_env = normalize_env(env) command = velociraptor_query_command( vql: vql, env: normalized_env, format: format, api_config: api_config, binary: binary ) result = run_command(command, timeout: timeout || option(:timeout)) result.merge(rows: parse_output(result[:stdout], format)) end |
#validate_artifact!(value) ⇒ Object
97 98 99 100 101 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 97 def validate_artifact!(value) return value.to_s if value.to_s.match?(ARTIFACT_PATTERN) raise ArgumentError, 'artifact must be a Velociraptor artifact name' end |
#validate_id!(value, label) ⇒ Object
91 92 93 94 95 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 91 def validate_id!(value, label) return value.to_s if value.to_s.match?(ID_PATTERN) raise ArgumentError, "#{label} must look like a Velociraptor id" end |
#velociraptor_query_command(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil) ⇒ Object
40 41 42 43 44 45 46 47 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 40 def velociraptor_query_command(vql:, env: {}, format: :jsonl, api_config: nil, binary: nil) command = [binary || option(:binary) || 'velociraptor'] config = api_config || option(:api_config) command += ['--api_config', config] if present?(config) command += ['query', vql.to_s, '--format', format.to_s] normalize_env(env).each { |key, value| command += ['--env', "#{key}=#{value}"] } command end |
#vql_list(values) ⇒ Object
87 88 89 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 87 def vql_list(values) Array(values).map { |value| vql_string(value) }.join(', ').then { |items| "[#{items}]" } end |
#vql_string(value) ⇒ Object
83 84 85 |
# File 'lib/legion/extensions/velociraptor/helpers/cli.rb', line 83 def vql_string(value) ::JSON.generate(value.to_s) end |