DSL and indirection question

M

Matt Lawrence

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.
 
J

James Edward Gray II

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.
=20
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 Gray II=
 
M

Matt Lawrence

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.
 
J

James Edward Gray II

On Tue, 26 Oct 2010, James Edward Gray II wrote:
=20 simple example or two?
=20
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
=20
def initialize(rule, result)
@rule =3D rule
@result =3D result
end
=20
attr_reader :rule
=20
def passed?
@result =3D=3D "pass"
end
=20
def failed?
@result =3D=3D "fail"
end
=20
def skipped?
@result =3D=3D "skipped"
end
end

st =3D SecurityTest.parse("12.34 fail")
puts st.rule
p st.failed?

Hope that helps.

James Edward Gray II=
 
J

Joel VanderWerf

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
 
R

Robert Klemme

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


I have a directory full of results from a security scan, on file per syst= em.
=A0In 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. =A0I know I can b= rute
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.

Rule =3D Struct.new :name do
def test(&b)
if b
@test =3D b
else
@test
end
end

# same for fix
end

AllRules =3D Hash.new {|h,k| h[k.freeze] =3D 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 =3D 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=3D result=3D

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

def ok?
result =3D=3D :pass
end
end

Something like this?

Cheers

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top