inspec 0.14.8 → 0.15.0

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -2
  3. data/bin/inspec +3 -4
  4. data/examples/inheritance/README.md +19 -0
  5. data/examples/inheritance/controls/example.rb +11 -0
  6. data/examples/inheritance/inspec.yml +10 -0
  7. data/lib/bundles/inspec-compliance/cli.rb +1 -4
  8. data/lib/bundles/inspec-supermarket/cli.rb +1 -4
  9. data/lib/inspec/dsl.rb +48 -55
  10. data/lib/inspec/profile.rb +6 -2
  11. data/lib/inspec/profile_context.rb +21 -8
  12. data/lib/inspec/runner.rb +17 -12
  13. data/lib/inspec/runner_rspec.rb +1 -0
  14. data/lib/inspec/version.rb +1 -1
  15. data/lib/resources/apache.rb +20 -18
  16. data/lib/resources/apache_conf.rb +92 -90
  17. data/lib/resources/apt.rb +92 -90
  18. data/lib/resources/audit_policy.rb +35 -33
  19. data/lib/resources/auditd_conf.rb +41 -39
  20. data/lib/resources/auditd_rules.rb +155 -153
  21. data/lib/resources/bond.rb +1 -1
  22. data/lib/resources/bridge.rb +97 -95
  23. data/lib/resources/command.rb +47 -45
  24. data/lib/resources/csv.rb +23 -21
  25. data/lib/resources/directory.rb +1 -1
  26. data/lib/resources/etc_group.rb +116 -114
  27. data/lib/resources/file.rb +1 -1
  28. data/lib/resources/gem.rb +39 -37
  29. data/lib/resources/group.rb +100 -98
  30. data/lib/resources/host.rb +103 -101
  31. data/lib/resources/inetd_conf.rb +42 -40
  32. data/lib/resources/ini.rb +15 -13
  33. data/lib/resources/interface.rb +106 -104
  34. data/lib/resources/iptables.rb +36 -34
  35. data/lib/resources/json.rb +64 -62
  36. data/lib/resources/kernel_module.rb +30 -28
  37. data/lib/resources/kernel_parameter.rb +44 -42
  38. data/lib/resources/limits_conf.rb +41 -39
  39. data/lib/resources/login_def.rb +38 -36
  40. data/lib/resources/mount.rb +43 -41
  41. data/lib/resources/mysql.rb +67 -65
  42. data/lib/resources/mysql_conf.rb +89 -87
  43. data/lib/resources/mysql_session.rb +46 -44
  44. data/lib/resources/npm.rb +35 -33
  45. data/lib/resources/ntp_conf.rb +44 -42
  46. data/lib/resources/oneget.rb +46 -44
  47. data/lib/resources/os.rb +22 -20
  48. data/lib/resources/os_env.rb +47 -45
  49. data/lib/resources/package.rb +213 -211
  50. data/lib/resources/parse_config.rb +59 -57
  51. data/lib/resources/passwd.rb +89 -87
  52. data/lib/resources/pip.rb +60 -58
  53. data/lib/resources/port.rb +352 -350
  54. data/lib/resources/postgres.rb +26 -24
  55. data/lib/resources/postgres_conf.rb +66 -64
  56. data/lib/resources/postgres_session.rb +47 -45
  57. data/lib/resources/processes.rb +56 -54
  58. data/lib/resources/registry_key.rb +150 -148
  59. data/lib/resources/script.rb +30 -28
  60. data/lib/resources/security_policy.rb +56 -54
  61. data/lib/resources/service.rb +638 -636
  62. data/lib/resources/shadow.rb +98 -96
  63. data/lib/resources/ssh_conf.rb +58 -56
  64. data/lib/resources/user.rb +363 -361
  65. data/lib/resources/windows_feature.rb +46 -44
  66. data/lib/resources/xinetd.rb +111 -109
  67. data/lib/resources/yaml.rb +16 -14
  68. data/lib/resources/yum.rb +107 -105
  69. data/lib/utils/base_cli.rb +18 -0
  70. data/test/helper.rb +2 -2
  71. data/test/unit/profile_context_test.rb +1 -1
  72. data/test/unit/resources/file_test.rb +1 -1
  73. data/test/unit/resources/mount_test.rb +1 -1
  74. metadata +5 -2
@@ -5,7 +5,7 @@
5
5
  require 'resources/file'
6
6
 
7
7
  module Inspec::Resources
8
- class Bond < File
8
+ class Bond < FileResource
9
9
  name 'bond'
10
10
  desc 'Use the bond InSpec audit resource to test a logical, bonded network interface (i.e. "two or more network interfaces aggregated into a single, logical network interface"). On Linux platforms, any value in the /proc/net/bonding directory may be tested.'
11
11
  example "
@@ -8,114 +8,116 @@
8
8
  # it { should have_interface 'eth0' }
9
9
  # end
10
10
 
11
- class Bridge < Inspec.resource(1)
12
- name 'bridge'
13
- desc 'Use the bridge InSpec audit resource to test basic network bridge properties, such as name, if an interface is defined, and the associations for any defined interface.'
14
- example "
15
- describe bridge 'br0' do
16
- it { should exist }
17
- it { should have_interface 'eth0' }
11
+ module Inspec::Resources
12
+ class Bridge < Inspec.resource(1)
13
+ name 'bridge'
14
+ desc 'Use the bridge InSpec audit resource to test basic network bridge properties, such as name, if an interface is defined, and the associations for any defined interface.'
15
+ example "
16
+ describe bridge 'br0' do
17
+ it { should exist }
18
+ it { should have_interface 'eth0' }
19
+ end
20
+ "
21
+
22
+ def initialize(bridge_name)
23
+ @bridge_name = bridge_name
24
+
25
+ @bridge_provider = nil
26
+ if inspec.os.linux?
27
+ @bridge_provider = LinuxBridge.new(inspec)
28
+ elsif inspec.os.windows?
29
+ @bridge_provider = WindowsBridge.new(inspec)
30
+ else
31
+ return skip_resource 'The `bridge` resource is not supported on your OS yet.'
32
+ end
18
33
  end
19
- "
20
-
21
- def initialize(bridge_name)
22
- @bridge_name = bridge_name
23
-
24
- @bridge_provider = nil
25
- if inspec.os.linux?
26
- @bridge_provider = LinuxBridge.new(inspec)
27
- elsif inspec.os.windows?
28
- @bridge_provider = WindowsBridge.new(inspec)
29
- else
30
- return skip_resource 'The `bridge` resource is not supported on your OS yet.'
31
- end
32
- end
33
-
34
- def exists?
35
- !bridge_info.nil? && !bridge_info[:name].nil?
36
- end
37
-
38
- def has_interface?(interface)
39
- return skip_resource 'The `bridge` resource does not provide interface detection for Windows yet' if inspec.os.windows?
40
- bridge_info.nil? ? false : bridge_info[:interfaces].include?(interface)
41
- end
42
34
 
43
- def interfaces
44
- bridge_info.nil? ? nil : bridge_info[:interfaces]
45
- end
35
+ def exists?
36
+ !bridge_info.nil? && !bridge_info[:name].nil?
37
+ end
46
38
 
47
- def to_s
48
- "Bridge #{@bridge_name}"
49
- end
39
+ def has_interface?(interface)
40
+ return skip_resource 'The `bridge` resource does not provide interface detection for Windows yet' if inspec.os.windows?
41
+ bridge_info.nil? ? false : bridge_info[:interfaces].include?(interface)
42
+ end
50
43
 
51
- private
44
+ def interfaces
45
+ bridge_info.nil? ? nil : bridge_info[:interfaces]
46
+ end
52
47
 
53
- def bridge_info
54
- return @cache if defined?(@cache)
55
- @cache = @bridge_provider.bridge_info(@bridge_name) if !@bridge_provider.nil?
56
- end
57
- end
48
+ def to_s
49
+ "Bridge #{@bridge_name}"
50
+ end
58
51
 
59
- class BridgeDetection
60
- attr_reader :inspec
61
- def initialize(inspec)
62
- @inspec = inspec
63
- end
64
- end
52
+ private
65
53
 
66
- # Linux Bridge
67
- # If /sys/class/net/{interface}/bridge exists then it must be a bridge
68
- # /sys/class/net/{interface}/brif contains the network interfaces
69
- # @see http://www.tldp.org/HOWTO/BRIDGE-STP-HOWTO/set-up-the-bridge.html
70
- # @see http://unix.stackexchange.com/questions/40560/how-to-know-if-a-network-interface-is-tap-tun-bridge-or-physical
71
- class LinuxBridge < BridgeDetection
72
- def bridge_info(bridge_name)
73
- # read bridge information
74
- bridge = inspec.file("/sys/class/net/#{bridge_name}/bridge").directory?
75
- return nil unless bridge
76
-
77
- # load interface names
78
- interfaces = inspec.command("ls -1 /sys/class/net/#{bridge_name}/brif/")
79
- interfaces = interfaces.stdout.chomp.split("\n")
80
- {
81
- name: bridge_name,
82
- interfaces: interfaces,
83
- }
54
+ def bridge_info
55
+ return @cache if defined?(@cache)
56
+ @cache = @bridge_provider.bridge_info(@bridge_name) if !@bridge_provider.nil?
57
+ end
84
58
  end
85
- end
86
59
 
87
- # Windows Bridge
88
- # select netadapter by adapter binding for windows
89
- # Get-NetAdapterBinding -ComponentID ms_bridge | Get-NetAdapter
90
- # @see https://technet.microsoft.com/en-us/library/jj130921(v=wps.630).aspx
91
- # RegKeys: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}
92
- class WindowsBridge < BridgeDetection
93
- def bridge_info(bridge_name)
94
- # find all bridge adapters
95
- cmd = inspec.command('Get-NetAdapterBinding -ComponentID ms_bridge | Get-NetAdapter | Select-Object -Property Name, InterfaceDescription | ConvertTo-Json')
96
-
97
- # filter network interface
98
- begin
99
- bridges = JSON.parse(cmd.stdout)
100
- rescue JSON::ParserError => _e
101
- return nil
60
+ class BridgeDetection
61
+ attr_reader :inspec
62
+ def initialize(inspec)
63
+ @inspec = inspec
102
64
  end
65
+ end
103
66
 
104
- # ensure we have an array of groups
105
- bridges = [bridges] if !bridges.is_a?(Array)
106
-
107
- # select the requested interface
108
- bridges = bridges.each_with_object([]) do |adapter, adapter_collection|
109
- # map object
110
- info = {
111
- name: adapter['Name'],
112
- interfaces: nil,
67
+ # Linux Bridge
68
+ # If /sys/class/net/{interface}/bridge exists then it must be a bridge
69
+ # /sys/class/net/{interface}/brif contains the network interfaces
70
+ # @see http://www.tldp.org/HOWTO/BRIDGE-STP-HOWTO/set-up-the-bridge.html
71
+ # @see http://unix.stackexchange.com/questions/40560/how-to-know-if-a-network-interface-is-tap-tun-bridge-or-physical
72
+ class LinuxBridge < BridgeDetection
73
+ def bridge_info(bridge_name)
74
+ # read bridge information
75
+ bridge = inspec.file("/sys/class/net/#{bridge_name}/bridge").directory?
76
+ return nil unless bridge
77
+
78
+ # load interface names
79
+ interfaces = inspec.command("ls -1 /sys/class/net/#{bridge_name}/brif/")
80
+ interfaces = interfaces.stdout.chomp.split("\n")
81
+ {
82
+ name: bridge_name,
83
+ interfaces: interfaces,
113
84
  }
114
- adapter_collection.push(info) if info[:name].casecmp(bridge_name) == 0
115
85
  end
86
+ end
116
87
 
117
- return nil if bridges.size == 0
118
- warn "[Possible Error] detected multiple bridges interfaces with the name #{bridge_name}" if bridges.size > 1
119
- bridges[0]
88
+ # Windows Bridge
89
+ # select netadapter by adapter binding for windows
90
+ # Get-NetAdapterBinding -ComponentID ms_bridge | Get-NetAdapter
91
+ # @see https://technet.microsoft.com/en-us/library/jj130921(v=wps.630).aspx
92
+ # RegKeys: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}
93
+ class WindowsBridge < BridgeDetection
94
+ def bridge_info(bridge_name)
95
+ # find all bridge adapters
96
+ cmd = inspec.command('Get-NetAdapterBinding -ComponentID ms_bridge | Get-NetAdapter | Select-Object -Property Name, InterfaceDescription | ConvertTo-Json')
97
+
98
+ # filter network interface
99
+ begin
100
+ bridges = JSON.parse(cmd.stdout)
101
+ rescue JSON::ParserError => _e
102
+ return nil
103
+ end
104
+
105
+ # ensure we have an array of groups
106
+ bridges = [bridges] if !bridges.is_a?(Array)
107
+
108
+ # select the requested interface
109
+ bridges = bridges.each_with_object([]) do |adapter, adapter_collection|
110
+ # map object
111
+ info = {
112
+ name: adapter['Name'],
113
+ interfaces: nil,
114
+ }
115
+ adapter_collection.push(info) if info[:name].casecmp(bridge_name) == 0
116
+ end
117
+
118
+ return nil if bridges.size == 0
119
+ warn "[Possible Error] detected multiple bridges interfaces with the name #{bridge_name}" if bridges.size > 1
120
+ bridges[0]
121
+ end
120
122
  end
121
123
  end
@@ -4,58 +4,60 @@
4
4
  # author: Christoph Hartmann
5
5
  # license: All rights reserved
6
6
 
7
- class Cmd < Inspec.resource(1)
8
- name 'command'
9
- desc 'Use the command InSpec audit resource to test an arbitrary command that is run on the system.'
10
- example "
11
- describe command('ls -al /') do
12
- it { should exist }
13
- its(:stdout) { should match /bin/ }
14
- its('stderr') { should eq '' }
15
- its(:exit_status) { should eq 0 }
7
+ module Inspec::Resources
8
+ class Cmd < Inspec.resource(1)
9
+ name 'command'
10
+ desc 'Use the command InSpec audit resource to test an arbitrary command that is run on the system.'
11
+ example "
12
+ describe command('ls -al /') do
13
+ it { should exist }
14
+ its(:stdout) { should match /bin/ }
15
+ its('stderr') { should eq '' }
16
+ its(:exit_status) { should eq 0 }
17
+ end
18
+ "
19
+
20
+ attr_reader :command
21
+
22
+ def initialize(cmd)
23
+ @command = cmd
16
24
  end
17
- "
18
25
 
19
- attr_reader :command
20
-
21
- def initialize(cmd)
22
- @command = cmd
23
- end
24
-
25
- def result
26
- @result ||= inspec.backend.run_command(@command)
27
- end
26
+ def result
27
+ @result ||= inspec.backend.run_command(@command)
28
+ end
28
29
 
29
- def stdout
30
- result.stdout
31
- end
30
+ def stdout
31
+ result.stdout
32
+ end
32
33
 
33
- def stderr
34
- result.stderr
35
- end
34
+ def stderr
35
+ result.stderr
36
+ end
36
37
 
37
- def exit_status
38
- result.exit_status.to_i
39
- end
38
+ def exit_status
39
+ result.exit_status.to_i
40
+ end
40
41
 
41
- def exist?
42
- # silent for mock resources
43
- return false if inspec.os[:family].to_s == 'unknown'
44
-
45
- if inspec.os.linux?
46
- res = inspec.backend.run_command("bash -c 'type \"#{@command}\"'")
47
- elsif inspec.os.windows?
48
- res = inspec.backend.run_command("where.exe \"#{@command}\"")
49
- elsif inspec.os.unix?
50
- res = inspec.backend.run_command("type \"#{@command}\"")
51
- else
52
- warn "`command(#{@command}).exist?` is not suported on your OS: #{inspec.os[:family]}"
53
- return false
42
+ def exist?
43
+ # silent for mock resources
44
+ return false if inspec.os[:family].to_s == 'unknown'
45
+
46
+ if inspec.os.linux?
47
+ res = inspec.backend.run_command("bash -c 'type \"#{@command}\"'")
48
+ elsif inspec.os.windows?
49
+ res = inspec.backend.run_command("where.exe \"#{@command}\"")
50
+ elsif inspec.os.unix?
51
+ res = inspec.backend.run_command("type \"#{@command}\"")
52
+ else
53
+ warn "`command(#{@command}).exist?` is not suported on your OS: #{inspec.os[:family]}"
54
+ return false
55
+ end
56
+ res.exit_status.to_i == 0
54
57
  end
55
- res.exit_status.to_i == 0
56
- end
57
58
 
58
- def to_s
59
- "Command #{@command}"
59
+ def to_s
60
+ "Command #{@command}"
61
+ end
60
62
  end
61
63
  end
data/lib/resources/csv.rb CHANGED
@@ -5,29 +5,31 @@
5
5
  # Parses a csv document
6
6
  # This implementation was inspired by a blog post
7
7
  # @see http://technicalpickles.com/posts/parsing-csv-with-ruby
8
- class CsvConfig < JsonConfig
9
- name 'csv'
10
- desc 'Use the csv InSpec audit resource to test configuration data in a CSV file.'
11
- example "
12
- describe csv('example.csv') do
13
- its('name') { should eq(['John', 'Alice']) }
14
- end
15
- "
8
+ module Inspec::Resources
9
+ class CsvConfig < JsonConfig
10
+ name 'csv'
11
+ desc 'Use the csv InSpec audit resource to test configuration data in a CSV file.'
12
+ example "
13
+ describe csv('example.csv') do
14
+ its('name') { should eq(['John', 'Alice']) }
15
+ end
16
+ "
16
17
 
17
- # override file load and parse hash from csv
18
- def parse(content)
19
- require 'csv'
20
- # convert empty field to nil
21
- CSV::Converters[:blank_to_nil] = lambda do |field|
22
- field && field.empty? ? nil : field
18
+ # override file load and parse hash from csv
19
+ def parse(content)
20
+ require 'csv'
21
+ # convert empty field to nil
22
+ CSV::Converters[:blank_to_nil] = lambda do |field|
23
+ field && field.empty? ? nil : field
24
+ end
25
+ # implicit conversion of values
26
+ csv = CSV.new(content, headers: true, converters: [:all, :blank_to_nil])
27
+ # convert to hash
28
+ csv.to_a.map(&:to_hash)
23
29
  end
24
- # implicit conversion of values
25
- csv = CSV.new(content, headers: true, converters: [:all, :blank_to_nil])
26
- # convert to hash
27
- csv.to_a.map(&:to_hash)
28
- end
29
30
 
30
- def to_s
31
- "Csv #{@path}"
31
+ def to_s
32
+ "Csv #{@path}"
33
+ end
32
34
  end
33
35
  end
@@ -5,7 +5,7 @@
5
5
  require 'resources/file'
6
6
 
7
7
  module Inspec::Resources
8
- class Directory < File
8
+ class Directory < FileResource
9
9
  name 'directory'
10
10
  desc 'Use the directory InSpec audit resource to test if the file type is a directory. This is equivalent to using the file InSpec audit resource and the be_directory matcher, but provides a simpler and more direct way to test directories. All of the matchers available to file may be used with directory.'
11
11
  example "
@@ -24,135 +24,137 @@
24
24
  require 'utils/convert'
25
25
  require 'utils/parser'
26
26
 
27
- class EtcGroup < Inspec.resource(1)
28
- include Converter
29
- include CommentParser
30
-
31
- name 'etc_group'
32
- desc 'Use the etc_group InSpec audit resource to test groups that are defined on Linux and UNIX platforms. The /etc/group file stores details about each group---group name, password, group identifier, along with a comma-separate list of users that belong to the group.'
33
- example "
34
- describe etc_group do
35
- its('gids') { should_not contain_duplicates }
36
- its('groups') { should include 'my_user' }
37
- its('users') { should include 'my_user' }
27
+ module Inspec::Resources
28
+ class EtcGroup < Inspec.resource(1)
29
+ include Converter
30
+ include CommentParser
31
+
32
+ name 'etc_group'
33
+ desc 'Use the etc_group InSpec audit resource to test groups that are defined on Linux and UNIX platforms. The /etc/group file stores details about each group---group name, password, group identifier, along with a comma-separate list of users that belong to the group.'
34
+ example "
35
+ describe etc_group do
36
+ its('gids') { should_not contain_duplicates }
37
+ its('groups') { should include 'my_user' }
38
+ its('users') { should include 'my_user' }
39
+ end
40
+ "
41
+
42
+ attr_accessor :gid, :entries
43
+ def initialize(path = nil)
44
+ @path = path || '/etc/group'
45
+ @entries = parse_group(@path)
46
+
47
+ # skip resource if it is not supported on current OS
48
+ return skip_resource 'The `etc_group` resource is not supported on your OS.' \
49
+ unless inspec.os.unix?
38
50
  end
39
- "
40
51
 
41
- attr_accessor :gid, :entries
42
- def initialize(path = nil)
43
- @path = path || '/etc/group'
44
- @entries = parse_group(@path)
45
-
46
- # skip resource if it is not supported on current OS
47
- return skip_resource 'The `etc_group` resource is not supported on your OS.' \
48
- unless inspec.os.unix?
49
- end
50
-
51
- def groups(filter = nil)
52
- entries = filter || @entries
53
- entries.map { |x| x['name'] } if !entries.nil?
54
- end
55
-
56
- def gids(filter = nil)
57
- entries = filter || @entries
58
- entries.map { |x| x['gid'] } if !entries.nil?
59
- end
60
-
61
- def users(filter = nil)
62
- entries = filter || @entries
63
- return nil if entries.nil?
64
- # filter the user entry
65
- res = entries.map { |x|
66
- x['members'].split(',') if !x.nil? && !x['members'].nil?
67
- }.flatten
68
- # filter nil elements
69
- res.reject { |x| x.nil? || x.empty? }
70
- end
71
-
72
- def where(conditions = {})
73
- return if conditions.empty?
74
- fields = {
75
- name: 'name',
76
- group_name: 'name',
77
- password: 'password',
78
- gid: 'gid',
79
- group_id: 'gid',
80
- users: 'members',
81
- members: 'members',
82
- }
83
- res = entries
84
-
85
- conditions.each do |k, v|
86
- idx = fields[k.to_sym]
87
- next if idx.nil?
88
- res = res.select { |x| x[idx] == v.to_s }
52
+ def groups(filter = nil)
53
+ entries = filter || @entries
54
+ entries.map { |x| x['name'] } if !entries.nil?
89
55
  end
90
56
 
91
- EtcGroupView.new(self, res)
92
- end
57
+ def gids(filter = nil)
58
+ entries = filter || @entries
59
+ entries.map { |x| x['gid'] } if !entries.nil?
60
+ end
93
61
 
94
- def to_s
95
- '/etc/group'
96
- end
62
+ def users(filter = nil)
63
+ entries = filter || @entries
64
+ return nil if entries.nil?
65
+ # filter the user entry
66
+ res = entries.map { |x|
67
+ x['members'].split(',') if !x.nil? && !x['members'].nil?
68
+ }.flatten
69
+ # filter nil elements
70
+ res.reject { |x| x.nil? || x.empty? }
71
+ end
97
72
 
98
- private
73
+ def where(conditions = {})
74
+ return if conditions.empty?
75
+ fields = {
76
+ name: 'name',
77
+ group_name: 'name',
78
+ password: 'password',
79
+ gid: 'gid',
80
+ group_id: 'gid',
81
+ users: 'members',
82
+ members: 'members',
83
+ }
84
+ res = entries
85
+
86
+ conditions.each do |k, v|
87
+ idx = fields[k.to_sym]
88
+ next if idx.nil?
89
+ res = res.select { |x| x[idx] == v.to_s }
90
+ end
91
+
92
+ EtcGroupView.new(self, res)
93
+ end
99
94
 
100
- def parse_group(path)
101
- @content = inspec.file(path).content
102
- if @content.nil?
103
- skip_resource "Can't access group file in #{path}"
104
- return []
95
+ def to_s
96
+ '/etc/group'
105
97
  end
106
- # iterate over each line and filter comments
107
- @content.split("\n").each_with_object([]) do |line, lines|
108
- grp_info = parse_group_line(line)
109
- lines.push(grp_info) if !grp_info.nil? && grp_info.size > 0
98
+
99
+ private
100
+
101
+ def parse_group(path)
102
+ @content = inspec.file(path).content
103
+ if @content.nil?
104
+ skip_resource "Can't access group file in #{path}"
105
+ return []
106
+ end
107
+ # iterate over each line and filter comments
108
+ @content.split("\n").each_with_object([]) do |line, lines|
109
+ grp_info = parse_group_line(line)
110
+ lines.push(grp_info) if !grp_info.nil? && grp_info.size > 0
111
+ end
110
112
  end
111
- end
112
113
 
113
- def parse_group_line(line)
114
- opts = {
115
- comment_char: '#',
116
- standalone_comments: false,
117
- }
118
- line, _idx_nl = parse_comment_line(line, opts)
119
- x = line.split(':')
120
- # abort if we have an empty or comment line
121
- return nil if x.size == 0
122
- # map data
123
- {
124
- 'name' => x.at(0), # Name of the group.
125
- 'password' => x.at(1), # Group's encrypted password.
126
- 'gid' => convert_to_i(x.at(2)), # The group's decimal ID.
127
- 'members' => x.at(3), # Group members.
128
- }
114
+ def parse_group_line(line)
115
+ opts = {
116
+ comment_char: '#',
117
+ standalone_comments: false,
118
+ }
119
+ line, _idx_nl = parse_comment_line(line, opts)
120
+ x = line.split(':')
121
+ # abort if we have an empty or comment line
122
+ return nil if x.size == 0
123
+ # map data
124
+ {
125
+ 'name' => x.at(0), # Name of the group.
126
+ 'password' => x.at(1), # Group's encrypted password.
127
+ 'gid' => convert_to_i(x.at(2)), # The group's decimal ID.
128
+ 'members' => x.at(3), # Group members.
129
+ }
130
+ end
129
131
  end
130
- end
131
132
 
132
- # object that hold a specifc view on etc group
133
- class EtcGroupView
134
- def initialize(parent, filter)
135
- @parent = parent
136
- @filter = filter
137
- end
133
+ # object that hold a specifc view on etc group
134
+ class EtcGroupView
135
+ def initialize(parent, filter)
136
+ @parent = parent
137
+ @filter = filter
138
+ end
138
139
 
139
- # returns the group object
140
- def entries
141
- @filter
142
- end
140
+ # returns the group object
141
+ def entries
142
+ @filter
143
+ end
143
144
 
144
- # only returns group name
145
- def groups
146
- @parent.groups(@filter)
147
- end
145
+ # only returns group name
146
+ def groups
147
+ @parent.groups(@filter)
148
+ end
148
149
 
149
- # only return gids
150
- def gids
151
- @parent.gids(@filter)
152
- end
150
+ # only return gids
151
+ def gids
152
+ @parent.gids(@filter)
153
+ end
153
154
 
154
- # only returns users
155
- def users
156
- @parent.users(@filter)
155
+ # only returns users
156
+ def users
157
+ @parent.users(@filter)
158
+ end
157
159
  end
158
160
  end