DSL and indirection question

I’m trying to figure out the best way of writing a script that describes
various requirements in the form of “12.34.56” (from a requirement
document) that I can then create methods for reporting, verifying and
remediating the requirment on a system.

This is script for checking and fixing systems based on a bunch of
security requirements. There are a couple of hundred rules and a few
hundred systems. I am thinking about building a hash of Procs, but I
think it is going to be too ugly. Any suggestions on a clean and easy
to
read way of doing this?

Thanks for the help, I am way too rusty on my Ruby programming.

– Matt
It’s not what I know that counts.
It’s what I can remember in time to use.

On Oct 25, 2010, at 2:20 PM, Matt L. wrote:

I’m trying to figure out the best way of writing a script that describes various
requirements in the form of “12.34.56” (from a requirement document) that I can
then create methods for reporting, verifying and remediating the requirment on a
system.

This is script for checking and fixing systems based on a bunch of security
requirements. There are a couple of hundred rules and a few hundred systems. I
am thinking about building a hash of Procs, but I think it is going to be too
ugly. Any suggestions on a clean and easy to read way of doing this?

This almost sounds like a job for Chef or Puppet, if I understood
correctly.

I’m not really getting what you are aiming for here. Can you show a
simple example or two?

James Edward G. II

On Tue, 26 Oct 2010, James Edward G. II wrote:

think it is going to be too ugly. Any suggestions on a clean and easy
to read way of doing this?

This almost sounds like a job for Chef or Puppet, if I understood
correctly.

Chef or Puppet would not be practical in this environment for various
reasons. This place is not in the Stone Age like my last job, they’re
more like the Bronze Age. I am campaigning to at least get Cfengine set
up.

I’m not really getting what you are aiming for here. Can you show a
simple example or two?

I have a directory full of results from a security scan, on file per
system. In that file each line starts with a rule number, like “12.34”
and has a pass/fail/skipped result.

What I probably want to do is to create a class for rules with each rule
having methods for testing and fixing each issue found. I know I can
brute force the script and it will look ugly or I can ask for help on
doing a nifty DSL in the new favoured Ruby style.

– Matt
It’s not what I know that counts.
It’s what I can remember in time to use.

On Oct 25, 2010, at 3:30 PM, Matt L. wrote:

On Tue, 26 Oct 2010, James Edward G. II wrote:

I’m not really getting what you are aiming for here. Can you show a simple
example or two?

I have a directory full of results from a security scan, on file per system. In
that file each line starts with a rule number, like “12.34” and has a
pass/fail/skipped result.

I’m probably still not understanding well, but this seems pretty easy to
model:

class SecurityTest
def self.parse(scan_result_line)
new(*scan_result_line.to_s.split)
end

def initialize(rule, result)
@rule = rule
@result = result
end

attr_reader :rule

def passed?
@result == “pass”
end

def failed?
@result == “fail”
end

def skipped?
@result == “skipped”
end
end

st = SecurityTest.parse(“12.34 fail”)
puts st.rule
p st.failed?

Hope that helps.

James Edward G. II

On Mon, Oct 25, 2010 at 10:30 PM, Matt L. [email protected]
wrote:

security requirements. There are a couple of hundred rules and a few

nifty DSL in the new favoured Ruby style.
Rule = Struct.new :name do
def test(&b)
if b
@test = b
else
@test
end
end

same for fix

end

AllRules = Hash.new {|h,k| h[k.freeze] = Rule[k]}

AllRules[“12.34”].test |system| puts “Testing rule on system #{system}”}
AllRules[“12.34”].fix {|system| puts “Fixing rule on system #{system}”}

or

AllRules[“12.34”].tap do |rule|
rule.test do |system|
puts “Testing rule on system #{system}”
end

rule.fix do |system|
puts “Fixing rule on system #{system}”
end
end

RuleResult = Struct.new :rule, :result do
def self.parse(str)
raise ArgumentError, “Cannot parse %p” % str unless
/^(\d+(?:.\d+)).(pass|fail|skip)/
self[AllRules[$1], $2.to_sym]
end

alias __result= result=

def result=(x)
__result= x.to_sym
end

def ok?
result == :pass
end
end

Something like this?

Cheers

robert

On 10/25/2010 12:20 PM, Matt L. wrote:

I’m trying to figure out the best way of writing a script that describes
various requirements in the form of “12.34.56” (from a requirement
document) that I can then create methods for reporting, verifying and
remediating the requirment on a system.

This is script for checking and fixing systems based on a bunch of
security requirements. There are a couple of hundred rules and a few
hundred systems. I am thinking about building a hash of Procs, but I
think it is going to be too ugly. Any suggestions on a clean and easy to
read way of doing this?

Maybe this helps, at least on the syntactic side (it’s still a hash of
procs underneath):

hash_builder = proc {|h,k| h[k] = Hash.new(&hash_builder)}
@rules = Hash.new(&hash_builder)
@stack = []

def section name, &block
begin
@stack.push name
yield
ensure
@stack.pop
end
end

def rule name, &block
section = @stack.inject(@rules) {|sect,n| sect[n]}
context = (@stack + [name]).join(".")
section[name] = proc do
block.call(context)
end
end

section 27 do
section “B” do
rule 6 do
puts “this is 27B-6”
end

 rule "foo" do |name|
   puts "this is #{name}"
 end

end
end

section 70 do
section 1 do
rule 9 do |name|
puts “this is rule #{name}”
end
end
end

require ‘pp’
pp @rules
puts
@rules[27][“B”][6].call
@rules[70][1][9].call

END

Output:

{27=>
{“B”=>
{6=>#Proc:0x00007f179675e590@-:17,
“foo”=>#Proc:0x00007f179675e590@-:17}},
70=>{1=>{9=>#Proc:0x00007f179675e590@-:17}}}

this is 27B-6
this is rule 70.1.9