dataMetaPii 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,71 @@
1
+ # DSL describing Connection between the PII abstract definition and application concretics
2
+ # This is full definition that can be parsed and structured.
3
+
4
+ ver "12.489.2.alpha"
5
+
6
+ # Reusable Attributes Division
7
+ attributes {
8
+ universalConstants {
9
+ piPositive: 3.14, # numers and decimal point: Float
10
+ piNegative: -3.14, # check the negative case
11
+ universe: "Forty-two",
12
+ @sam# reference to the reusable, see further down
13
+ }
14
+ ints {
15
+ maxInstanceCount: 0012, # numbers only, no decimal point: perceived/rendered as an Integer
16
+ foo: -019 # check the negative case; note that octal conversion does not apply like with literals in Ruby code
17
+ }
18
+ sam { # Can the parser handle strings with C-like backslash escapes?
19
+ says: "Sam \t says, \"You kidding me, right?\"",
20
+ @donald # should be able to handle cycles in the inclusion tree
21
+ }
22
+ donald {
23
+ quacks: "Quack!",
24
+ @sam # should be able to handle cycles in the inclusion tree
25
+ }
26
+ # see if the parser can handle a one-liner
27
+ noise { @donald, spectrum: "white", @sam, @ints }
28
+ }
29
+
30
+ # Application Division
31
+ apps {
32
+ pollingServices { # Unique application ID; should be unique throughout the config, each app responsible for its own def
33
+ # or make it centralized, standard??
34
+ Name_Full { # the PII key from the abstract definition
35
+ # Application-specific attributes for this field (need to standardize them?):
36
+
37
+ # DataMeta DOM record's name, without the version let alone the package: the application
38
+ # should be aware of those details and be flexible. From this, can infer the InOutable and migration calls
39
+ voClass: Name,
40
+ # list of database fields that store this value
41
+ bigTableFields: "users:name, clients:fullName",
42
+ @ints # reference to the reusables
43
+ }
44
+
45
+ TwoFA_Token_Serial_Number {
46
+ voClass: TwoFaSerialNumber,
47
+ bigTableFields: "security:twoFa",
48
+ @universalConstants,@ints
49
+ }
50
+ }
51
+
52
+ bcastingServices {
53
+ Name_First {
54
+ voClass: Name,
55
+ oracleFields: "USERS:FIRST_NAME",
56
+ lapseCount: 0123,
57
+ median: -123.4567,
58
+ weight: 987.65432
59
+ }
60
+ Name_Last {
61
+ voClass: Name,
62
+ oracleFields: "USERS:LAST_NAME"
63
+ }
64
+ Date_Of_Birth {
65
+ voClass: BirthDate, # plain symbol, no enclosure: perceived/rendered as a string
66
+ logFormat: "yyyy-MM-dd HH:mm:SS", # enclosured in a string: perceived/rendered as a string
67
+ @universalConstants,
68
+ bigTableFields: "users:dob,clients:birthDate" # enclosured in a string: perceived/rendered as a string
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,35 @@
1
+ # DSL describing Connection between the PII abstract definition and application concretics
2
+ # This is full definition that can be parsed and structured.
3
+ # For testing/structuring purposes, the attributes division is missing and
4
+ # no reusables are referred to.
5
+
6
+ ver "3.423.11.19"
7
+
8
+ # Application Division
9
+ apps {
10
+ pollingServices { # Unique application ID; should be unique throughout the config, each app responsible for its own def
11
+ # or make it centralized, standard??
12
+ Name_Full { # the PII key from the abstract definition
13
+ # Application-specific attributes for this field (need to standardize them?):
14
+
15
+ # DataMeta DOM record's name, without the version let alone the package: the application
16
+ # should be aware of those details and be flexible. From this, can infer the InOutable and migration calls
17
+ voClass: Name,
18
+ # list of database fields that store this value
19
+ oracleFields: "users:name, clients:fullName"
20
+ }
21
+
22
+ TwoFA_Token_Serial_Number {
23
+ voClass: TwoFaSerialNumber,
24
+ oracleFields: "security:twoFa"
25
+ }
26
+ }
27
+
28
+ bcastingServices {
29
+ Date_Of_Birth {
30
+ voClass: BirthDate, # plain symbol, no enclosure: perceived/rendered as a string
31
+ logFormat: "yyyy-MM-dd HH:mm:SS", # enclosured in a string: perceived/rendered as a string
32
+ oracleFields: "users:dob,clients:birthDate" # enclosured in a string: perceived/rendered as a string
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,73 @@
1
+ # This definition is for grammar testing/debugging only.
2
+ # An attempt to pass it through structuring should fail because there are intentional violations
3
+ # of a exogrammatical structure: for example, multiple VO definitions are allowed by the grammar
4
+ # but the CST builder rejects those with an error.
5
+
6
+ ver "1.2.3.4.beta" # Full version presented here
7
+
8
+ # Reusable Attributes Division
9
+ attributes {
10
+ universalConstants {
11
+ piPositive: 3.14, # numers and decimal point: Float
12
+ piNegative: -3.14, # check the negative case
13
+ universe: "Forty-two",
14
+ @sam, # reference to the reusable, see further down
15
+ @symbolSoloOnLine,
16
+ boo: 1.23, foo:-35.36,
17
+ @symbolLeadinWsAndTrailingComment, # endline comment for this
18
+ @symbolWithTrailingComment, # endline comment
19
+ @symbolWithLeadingWhitespace, str:"Some \n string"
20
+ }
21
+ ints {
22
+ maxInstanceCount: 4, # numbers only, no decimal point: perceived/rendered as an Integer
23
+ foo: -4 # check the negative case
24
+ }
25
+ sam { # Can the parser handle strings with C-like backslash escapes?
26
+ says: "Sam \t says, \"You kidding me, right?\""
27
+ }
28
+ donald {
29
+ quacks: "Quack!"
30
+ }
31
+ # see if the parser can handle a one-liner
32
+ noise { @donald, spectrum: "white", @sam }
33
+ }
34
+
35
+ # Application Division
36
+ apps {
37
+ pollingServices { # Unique application ID; should be unique throughout the config, each app responsible for its own def
38
+ # or make it centralized, standard??
39
+ Name_Full { # the PII key from the abstract definition
40
+ # Application-specific attributes for this field (need to standardize them?):
41
+
42
+ # DataMeta DOM record's name, without the version let alone the package: the application
43
+ # should be aware of those details and be flexible. From this, can infer the InOutable and migration calls
44
+ voClass: Name,
45
+ # list of database fields that store this value
46
+ mySqlFields: "users:name, clients:fullName",
47
+ @ints # reference to the reusables
48
+ }
49
+
50
+ TwoFA_Token_Serial_Number {
51
+ voClass: TwoFaSerialNumber,
52
+ db2Fields: "security:twoFa",
53
+ @universalConstants,@ints
54
+ }
55
+ } # try this
56
+ bcastingServices {
57
+ Date_Of_Birth {
58
+ voClass:FirstClass,
59
+ voClass: SecondClass,
60
+ voClass : ThirdClass,
61
+ voClass :FourthClass,
62
+ # Leading space
63
+ voClass: FifthClass,
64
+ voClass: SixthClass, # tail comment
65
+ voClass :SeventhClass # tail with no leading whitespace
66
+ }
67
+ TwoFA_Token_Serial_Number {
68
+ voClass: TwoFaSerialNumber,
69
+ bigTableFields: "security:twoFa",
70
+ @universalConstants,@ints
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,28 @@
1
+ # Master Definition Of the PII fields
2
+ # the "taboo" level means that under no circumstances the value should be stored.
3
+
4
+ # PII field definition format:
5
+ # PII-Field-UniqueKey {PROFILE-KEY {level=IMPACT_LEVEL}}
6
+
7
+ # These impact levels are picked at random for testing, check with your company's policies
8
+ # for real impact levels.
9
+
10
+ ver "1.0.0"
11
+
12
+ Corp_User_Name { # PII field unique key
13
+ level=taboo # "taboo" : in this profile, under no circumstances this field can be stored or rendered in the logs
14
+ }
15
+
16
+ Date_Of_Birth { level=restricted }
17
+
18
+ TwoFA_Token {level=confidential, dataType=access}
19
+
20
+ Home_City {level=confidential, dataType=location}
21
+ Home_Country {level=confidential}
22
+ Home_State {level=confidential} # State or Province
23
+ Home_Zip {level=confidential} # U.S. ZIP code
24
+ Name_First {level=confidential}
25
+ Name_Last {level=internal}
26
+ Name_Middle {level=public}
27
+ Name_Full {level=confidential,enabled=true, owner=nameKeeper}
28
+
@@ -0,0 +1,42 @@
1
+ # keep this underscore naming in the test subdir, it's easier to append files names to test
2
+ require './test/test_helper.rb'
3
+
4
+ =begin rdoc
5
+ Unit test cases for the DataMetaPii
6
+ =end
7
+ class TestNewGem < Test::Unit::TestCase
8
+ include DataMetaPiiTests
9
+
10
+ # an empty stub for now
11
+ def setup;
12
+ @impactConstVals = DataMetaPii::Impact.constants.map{|c| ":#{DataMetaPii::Impact.const_get(c)}"}
13
+ end
14
+
15
+ =begin rdoc
16
+ Test obtaining a constant list from a module
17
+ =end
18
+ def test_constantList
19
+ v = DataMetaPii::RegKeyVo.new('A_PII_field',
20
+ {DataMetaPii::RegKeyVo::LEVEL => DataMetaPii::Impact::CONFIDENTIAL, "foo" => "bar", "val" => 123.456})
21
+
22
+ L.info(%<Impact constants: #{DataMetaPii::Impact.constants.map{|c| "#{c}=#{DataMetaPii::Impact.const_get(c)}"}.join('; ')}
23
+ first PII VO created: #{v.to_tree_image(DataMetaPii::INDENT)}
24
+ >)
25
+ xcp = assert_raise(ArgumentError) { DataMetaPii::RegKeyVo.new('A_PII_field', {DataMetaPii::RegKeyVo::LEVEL => ''}) }
26
+ assert(xcp.message.start_with?('Impact level missing or empty in'))
27
+
28
+ xcp = assert_raise(ArgumentError) { DataMetaPii::RegKeyVo.new('A_PII_field', {'foo' => 'bar'}) }
29
+ assert(xcp.message.start_with?('Impact level missing or empty in'))
30
+
31
+ xcp = assert_raise(ArgumentError) { DataMetaPii::RegKeyVo.new('A PII field',
32
+ {DataMetaPii::RegKeyVo::LEVEL => DataMetaPii::Impact::CONFIDENTIAL}) }
33
+
34
+ assert(xcp.message.start_with?('Invalid PII key: '))
35
+
36
+ xcp = assert_raise(ArgumentError) { DataMetaPii::RegKeyVo.new('A_PII_field',
37
+ {DataMetaPii::RegKeyVo::LEVEL => :bad_impact_level}) }
38
+
39
+ L.info(%<Testing #{:bad_impact_level}: #{xcp.message}\n#{xcp.backtrace.join("\n\t")}\n>)
40
+ assert(xcp.message.start_with?('Unsupported Impact Level '))
41
+ end
42
+ end
@@ -0,0 +1,152 @@
1
+ require './test/test_helper.rb'
2
+
3
+ =begin rdoc
4
+ Test for the DataMetaPii grammars and parsing.
5
+
6
+ Assertions: http://ruby-doc.org/stdlib-1.9.3/libdoc/test/unit/rdoc/Test/Unit/Assertions.html
7
+ =end
8
+ class TestPiiFmts < Test::Unit::TestCase
9
+
10
+ include DataMetaPiiTests
11
+
12
+ # loads the fmt grammar and creates the parser instance
13
+ def setup
14
+
15
+ @registryParser = PiiRegistryParser.new
16
+ @piiAppLinkParser = PiiAppLinkParser.new
17
+ L.info %<DataMeta PII Registry parser: #{@registryParser.inspect}
18
+ DataMeta PII App Link parser: #{@piiAppLinkParser.inspect}
19
+ >
20
+ end
21
+
22
+ =begin rdoc
23
+ Test Pii Registry DML parsing
24
+ =end
25
+ def test_registry_parse
26
+ ast = DataMetaParse.parse(@registryParser, IO.read('./test/registryShowcase.dmPii'))
27
+ L.info 'Registry parse start'
28
+ raise 'Registry File Format parse unsuccessful' unless ast
29
+ raise ast if ast.is_a?(DataMetaParse::Err)
30
+ #L.info "AST:\n#{ast.fields.inspect}"
31
+ #L.info "----------AST:\n#{ast.inspect}"
32
+ #elems = [ast.items.elements]
33
+ #elems = [ast.fields]
34
+ #L.info "===========AST Fields:\n#{elems.inspect}\n==================="
35
+ ast.fields.elements.each { |f|
36
+ L.info("PII Key: #{f.pk}: #{f.attrbLst.attrbs.map{|e| "#{e.k}::#{e.v}"}.join('; ')}")
37
+ }
38
+ L.info(%<PII Registry:
39
+ #{DataMetaPii.buildRegCst(ast).to_tree_image(DataMetaPii::INDENT)}>)
40
+ end
41
+
42
+ =begin rdoc
43
+ Test Pii Registry DML parsing and structuring - full version
44
+ =end
45
+ def test_app_link_parse_full
46
+ L.info 'Full applink parse start'
47
+ ast = DataMetaParse.parse(@piiAppLinkParser, IO.read('./test/appLinkFull.dmPii'))
48
+ raise 'Full AppLink parse unsuccessful' unless ast
49
+ if ast.is_a?(DataMetaParse::Err)
50
+ raise %<#{ast.parser.failure_line}
51
+ #{ast.parser.failure_reason}>
52
+ end
53
+ #L.info "AST:\n#{ast.fields.inspect}"
54
+ #L.info "----------AST:\n#{ast.inspect}"
55
+ #elems = [ast.items.elements]
56
+ #elems = [ast.fields]
57
+ #L.info "===========AST Fields:\n#{elems.inspect}\n==================="
58
+ ast.elements[1].elements.each { |f|
59
+ if f.respond_to?(:type) && f.type == 'refVal'
60
+ L.info(%<refVal: #{f.sym}>)
61
+ else
62
+ L.info(%<AppLink Elem: #{f.inspect}>)
63
+ end
64
+ }
65
+ ast.elements[3].elements.each { |f|
66
+ if f.respond_to?(:type) && f.type == 'refVal'
67
+ L.info(%<refVal: #{f.sym}>)
68
+ else
69
+ L.info(%<AppLink Elem: #{f.inspect}>)
70
+ end
71
+ }
72
+ log = ''
73
+ appLinkObj = DataMetaPii.buildAlCst(ast, log)
74
+
75
+ L.info(%<AppLink Full:
76
+ #{appLinkObj}
77
+ Building log:
78
+ #{log}
79
+ >)#.to_tree_image(DataMetaPii::INDENT_STEP)}>)
80
+
81
+ end
82
+
83
+ def test_app_link_parse_method
84
+ appLinkModel = DataMetaPii.parseAppLink(IO.read('./test/appLinkFull.dmPii'))
85
+ L.info(%<AppLink Model - full:
86
+ #{appLinkModel.inspect}>)
87
+ end
88
+
89
+ =begin rdoc
90
+ Test Pii Registry DML parsing - showcase version, do not run this tree through CST builder!
91
+ =end
92
+ def test_app_link_parse_showcase
93
+ L.info 'Showcase applink parse start'
94
+ ast = DataMetaParse.parse(@piiAppLinkParser, IO.read('./test/appLinkShowcase.dmPii'))
95
+ raise 'Showcase File Format parse unsuccessful' unless ast
96
+ if ast.is_a?(DataMetaParse::Err)
97
+ raise %<#{ast.parser.failure_line}
98
+ #{ast.parser.failure_reason}>
99
+ end
100
+ #L.info "AST:\n#{ast.fields.inspect}"
101
+ #L.info "----------AST:\n#{ast.inspect}"
102
+ #elems = [ast.items.elements]
103
+ #elems = [ast.fields]
104
+ #L.info "===========AST Fields:\n#{elems.inspect}\n==================="
105
+ ast.elements[1].elements.each { |f|
106
+ if f.respond_to?(:type) && f.type == 'refVal'
107
+ L.info(%<refVal: #{f.sym}>)
108
+ else
109
+ L.info(%<AppLink Elem: #{f.inspect}>)
110
+ end
111
+ }
112
+ ast.elements[3].elements.each { |f|
113
+ if f.respond_to?(:type) && f.type == 'refVal'
114
+ L.info(%<refVal: #{f.sym}>)
115
+ else
116
+ L.info(%<AppLink Elem: #{f.inspect}>)
117
+ end
118
+ }
119
+ end
120
+
121
+ =begin rdoc
122
+ Test Pii Registry DML parsing - version with no reusables, must be successfully processed by the CST builder
123
+ =end
124
+ def test_app_link_parse_no_reusables
125
+ L.info 'No-reusables applink parse start'
126
+ ast = DataMetaParse.parse(@piiAppLinkParser, IO.read('./test/appLinkNoReusables.dmPii'))
127
+ raise 'No-reusables File Format parse unsuccessful' unless ast
128
+ if ast.is_a?(DataMetaParse::Err)
129
+ raise %<#{ast.parser.failure_line}
130
+ #{ast.parser.failure_reason}>
131
+ end
132
+ #L.info "AST:\n#{ast.fields.inspect}"
133
+ #L.info "----------AST:\n#{ast.inspect}"
134
+ #elems = [ast.items.elements]
135
+ #elems = [ast.fields]
136
+ #L.info "===========AST Fields:\n#{elems.inspect}\n==================="
137
+ ast.elements[0].elements.each { |f|
138
+ if f.respond_to?(:type) && f.type == 'refVal'
139
+ L.info(%<refVal: #{f.sym}>)
140
+ else
141
+ L.info(%<AppLink Elem: #{f.inspect}>)
142
+ end
143
+ }
144
+ log = ''
145
+ applinkObj = DataMetaPii.buildAlCst(ast, log)
146
+ L.info(%<AppLink No Reusables:
147
+ #{applinkObj.inspect}
148
+ Building log:
149
+ #{log}
150
+ >)#.to_tree_image(DataMetaPii::INDENT_STEP)}>)
151
+ end
152
+ end
@@ -0,0 +1,24 @@
1
+ ## keep this underscore naming in the test subdir, it's easier to append files names to test
2
+ %w(stringio test/unit).each { |r| require r }
3
+ # this is expected to run from the project root, normally by the rake file
4
+
5
+ $VERBOSE = false # turn off noisy for the 1st release
6
+
7
+ require './lib/dataMetaPii'
8
+ require 'logger'
9
+ require 'dataMetaParse'
10
+
11
+ module DataMetaPiiTests
12
+
13
+ L = Logger.new('piiTests.log', 0, 10_000_000)
14
+ L.level = Logger::DEBUG
15
+ L.datetime_format = '%Y-%m-%d %H:%M:%S'
16
+
17
+ # By the way, inspecting a parser does not make any difference compared to just to_s:
18
+ L.info(%<Loaded base rules: #{DataMetaPii::BASE_RULES}
19
+
20
+ Loaded PII Commons Rules: #{DataMetaPii::PII_COMMONS.inspect}
21
+ Loaded Regstry Rules: #{DataMetaPii::REGISTRY}
22
+ Loaded AppLink Rules: #{DataMetaPii::APP_LINK}
23
+ >)
24
+ end
@@ -0,0 +1,64 @@
1
+ package <%= namespace %>;
2
+
3
+ /*
4
+ **************** This file is generated by DataMeta; do not edit manually!!
5
+ */
6
+
7
+ import java.util.HashMap;
8
+ import java.util.Map;
9
+
10
+ import static java.util.Collections.unmodifiableMap;
11
+
12
+ /**
13
+ * The encapsulation of the version <%= reg.ver %> of the Abstract PII definition.
14
+ */
15
+ public class <%= className %> {
16
+ <% reg.keyVos.keys.sort.each { |k| fldName = k.to_s.inspect; %>
17
+ public final static String <%= k.to_s %> = <%=fldName%>;
18
+ <%}%>
19
+
20
+ /**
21
+ * Impact Levels:
22
+ */
23
+ public static enum Level {
24
+ <%= (codeIndent * 3)[0..-2] %><%= ALL_IMPACTS.map{|i| i.to_s.upcase}.join(",\n#{(codeIndent * 3)[0..-2]}") %>
25
+
26
+ }
27
+
28
+ /**
29
+ * One abstract key definition encapsulation.
30
+ */
31
+ public static class Def {
32
+ private final String key;
33
+ private final Level level;
34
+ private final Map<String, String> props;
35
+
36
+ public Def(String key, final Level level, final Map<String, String> props) {
37
+ this.key = key;
38
+ this.level = level;
39
+ this.props = props;
40
+ }
41
+
42
+ public Level getLevel() { return level; }
43
+
44
+ public Map<String, String> getProps() { return props; }
45
+
46
+ public String getKey() { return key; }
47
+ }
48
+
49
+ /**
50
+ * The map keyed by field name pointing to the matching instance of the {@link Def} class.
51
+ */
52
+ public static final Map<String, Def> DEFS = unmodifiableMap(new HashMap<String, Def>() {
53
+ {
54
+ <% reg.keyVos.keys.sort.each { |k| fldName = k.to_s; fldDef = reg.keyVos[k] %>
55
+ put(<%= fldName %>, new Def(<%= fldName %>, Level.<%= fldDef.level.to_s.upcase %>, unmodifiableMap(new HashMap<String, String>() {
56
+ {<% fldDef.attrs.keys.sort.each {|k| keyStr = k.to_s.inspect; valStr = fldDef.attrs[k].inspect %>
57
+ put(<%=keyStr%>, <%=valStr%>); <% } %>
58
+ }
59
+ })));
60
+ <% } %>
61
+ }
62
+ });
63
+ }
64
+