dataMetaPii 1.0.1

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.
@@ -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
+