cyberark-tpc-plugin-validator 0.2.0__py3-none-any.whl

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 (41) hide show
  1. cyberark_tpc_plugin_validator-0.2.0.dist-info/METADATA +45 -0
  2. cyberark_tpc_plugin_validator-0.2.0.dist-info/RECORD +41 -0
  3. cyberark_tpc_plugin_validator-0.2.0.dist-info/WHEEL +5 -0
  4. cyberark_tpc_plugin_validator-0.2.0.dist-info/entry_points.txt +2 -0
  5. cyberark_tpc_plugin_validator-0.2.0.dist-info/licenses/LICENSE +21 -0
  6. cyberark_tpc_plugin_validator-0.2.0.dist-info/top_level.txt +1 -0
  7. tpc_plugin_validator/__init__.py +1 -0
  8. tpc_plugin_validator/lexer/__init__.py +1 -0
  9. tpc_plugin_validator/lexer/lexer.py +221 -0
  10. tpc_plugin_validator/lexer/tokens/__init__.py +1 -0
  11. tpc_plugin_validator/lexer/tokens/assignment.py +16 -0
  12. tpc_plugin_validator/lexer/tokens/comment.py +14 -0
  13. tpc_plugin_validator/lexer/tokens/cpm_parameter_validation.py +17 -0
  14. tpc_plugin_validator/lexer/tokens/fail_state.py +16 -0
  15. tpc_plugin_validator/lexer/tokens/section_header.py +14 -0
  16. tpc_plugin_validator/lexer/tokens/transition.py +16 -0
  17. tpc_plugin_validator/lexer/utilities/__init__.py +1 -0
  18. tpc_plugin_validator/lexer/utilities/regex.py +10 -0
  19. tpc_plugin_validator/lexer/utilities/token_name.py +14 -0
  20. tpc_plugin_validator/lexer/utilities/types.py +22 -0
  21. tpc_plugin_validator/main.py +41 -0
  22. tpc_plugin_validator/parser/__init__.py +1 -0
  23. tpc_plugin_validator/parser/parser.py +91 -0
  24. tpc_plugin_validator/rule_sets/__init__.py +1 -0
  25. tpc_plugin_validator/rule_sets/conditions_section_rule_set.py +88 -0
  26. tpc_plugin_validator/rule_sets/cpm_parameters_validation_section_rule_set.py +96 -0
  27. tpc_plugin_validator/rule_sets/debug_information_section_rule_set.py +154 -0
  28. tpc_plugin_validator/rule_sets/file_rule_set.py +82 -0
  29. tpc_plugin_validator/rule_sets/parameters_section_rule_set.py +135 -0
  30. tpc_plugin_validator/rule_sets/process_file_rule_set.py +47 -0
  31. tpc_plugin_validator/rule_sets/prompts_file_rule_set.py +40 -0
  32. tpc_plugin_validator/rule_sets/rule_set.py +157 -0
  33. tpc_plugin_validator/rule_sets/section_rule_set.py +48 -0
  34. tpc_plugin_validator/rule_sets/states_section_rule_set.py +128 -0
  35. tpc_plugin_validator/rule_sets/transitions_section_rule_set.py +158 -0
  36. tpc_plugin_validator/utilities/__init__.py +1 -0
  37. tpc_plugin_validator/utilities/exceptions.py +13 -0
  38. tpc_plugin_validator/utilities/severity.py +11 -0
  39. tpc_plugin_validator/utilities/types.py +53 -0
  40. tpc_plugin_validator/utilities/validation_result.py +14 -0
  41. tpc_plugin_validator/validator.py +75 -0
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: cyberark-tpc-plugin-validator
3
+ Version: 0.2.0
4
+ Summary: A tool to help validate a custom TPC plugin.
5
+ Author-email: Peter McDonald <git@petermcdonald.co.uk>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 (Peter McDonald)
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: Programming Language :: Python
30
+ Classifier: Programming Language :: Python :: 3.11
31
+ Classifier: Programming Language :: Python :: 3.12
32
+ Classifier: Programming Language :: Python :: 3.13
33
+ Classifier: Programming Language :: Python :: 3.14
34
+ Classifier: Programming Language :: Python :: 3.15
35
+ Classifier: Typing :: Typed
36
+ Requires-Python: >=3.11
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Dynamic: license-file
40
+
41
+ # CyberArk TPC Plugin Validator
42
+
43
+ This repository is a placeholder for a new package that is intended to validate CyberArk TPC plugins. The package will
44
+ include a set of tools and scripts to ensure that the plugins meet the required standards and function correctly within
45
+ the CyberArk environment.
@@ -0,0 +1,41 @@
1
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/licenses/LICENSE,sha256=3uaL9bRy1TQRSsUyzskLL1GTXFYzmd7Aew6JlPpZJq0,1073
2
+ tpc_plugin_validator/__init__.py,sha256=d1YTr2Y253X8hS3_f9AfooOp8aG7y2nkLrvJ5qgNUrQ,73
3
+ tpc_plugin_validator/main.py,sha256=jGKlE7T5pJGuSINqRd8nivfV7uiGG1sxNrou45u5a5A,1493
4
+ tpc_plugin_validator/validator.py,sha256=Cgc5WdkxWuiliO9gbWVO5GJE5Ru6xCDtR3waMcmQmJs,2544
5
+ tpc_plugin_validator/lexer/__init__.py,sha256=eIdZea9EkshGJmN09wsnUVm661sTy2UH83h4kSfufgQ,69
6
+ tpc_plugin_validator/lexer/lexer.py,sha256=9eTN6zDI3ADC_7Ev7zv72m-Q8rP2GUpmiNBAP-lgTQo,7341
7
+ tpc_plugin_validator/lexer/tokens/__init__.py,sha256=d1YTr2Y253X8hS3_f9AfooOp8aG7y2nkLrvJ5qgNUrQ,73
8
+ tpc_plugin_validator/lexer/tokens/assignment.py,sha256=mYyXioEp6pZ-hJ5EgjXHF_xQtilgRgClOAzCi5BlsJs,404
9
+ tpc_plugin_validator/lexer/tokens/comment.py,sha256=J77JpxAGeTWl0WPuXzB2V5NRGH8odjmML_KLSsK8S-g,318
10
+ tpc_plugin_validator/lexer/tokens/cpm_parameter_validation.py,sha256=cYukUa1p38qukrSsp_9jb1jA9C19c0NNOewrP80yfgs,467
11
+ tpc_plugin_validator/lexer/tokens/fail_state.py,sha256=MH-WRBXzZUtvBOORtbXNV7a-W05gxuEbi0bpM-fKDdc,357
12
+ tpc_plugin_validator/lexer/tokens/section_header.py,sha256=SCCtsTerV5fltafjsrXSCWbBqDtN0WkaRn_GR1Mr8K0,347
13
+ tpc_plugin_validator/lexer/tokens/transition.py,sha256=tFSIo3mYYrZ7T-dvAJCbkCQ7fihwIgiXUQpPhz2RV7E,386
14
+ tpc_plugin_validator/lexer/utilities/__init__.py,sha256=d1YTr2Y253X8hS3_f9AfooOp8aG7y2nkLrvJ5qgNUrQ,73
15
+ tpc_plugin_validator/lexer/utilities/regex.py,sha256=XwlXZsMZg8oCT-6C_hF_ENxA4ahQbU72y4JUR_NRx-Q,865
16
+ tpc_plugin_validator/lexer/utilities/token_name.py,sha256=HS1gthkYXEdV2bAePT2zdaWyf-Y3IwNnZ_r2uFOsEnA,343
17
+ tpc_plugin_validator/lexer/utilities/types.py,sha256=v5gz8ogUhy6ZrK0eBCxCupzcp0B6uT_oTZ2tFYkfHZY,831
18
+ tpc_plugin_validator/parser/__init__.py,sha256=eIdZea9EkshGJmN09wsnUVm661sTy2UH83h4kSfufgQ,69
19
+ tpc_plugin_validator/parser/parser.py,sha256=GnsK-AsaqVjDB4_GAYPZi0picZx-S2DRUCKygHgmt7Y,3077
20
+ tpc_plugin_validator/rule_sets/__init__.py,sha256=d1YTr2Y253X8hS3_f9AfooOp8aG7y2nkLrvJ5qgNUrQ,73
21
+ tpc_plugin_validator/rule_sets/conditions_section_rule_set.py,sha256=nxQW8BDFfrTeJdlP5juryIypDYp1E4KpIg3ApZqpT_U,3725
22
+ tpc_plugin_validator/rule_sets/cpm_parameters_validation_section_rule_set.py,sha256=yeOZQ9th4LJkiWJZtNp_7QDw7Y18i_bKWNZ5SqqSkeI,3719
23
+ tpc_plugin_validator/rule_sets/debug_information_section_rule_set.py,sha256=TrvDCIcuzMBhHfBczFQ7fw7fvdPyntYTxICnszviAWg,6202
24
+ tpc_plugin_validator/rule_sets/file_rule_set.py,sha256=QwNu7QyqOS7eX5HcJQmajl3xQFqkib8uiaqv0oM0XQ0,3494
25
+ tpc_plugin_validator/rule_sets/parameters_section_rule_set.py,sha256=XnlFF9hPm0IWLNqlMM_rrDxUA88qO7QMx6Y6pbxj2EA,5626
26
+ tpc_plugin_validator/rule_sets/process_file_rule_set.py,sha256=OHuOgYhhLvyWniPCa6liM2r8ozxXfWk86pfCKyc4vgM,2068
27
+ tpc_plugin_validator/rule_sets/prompts_file_rule_set.py,sha256=xkp-F3vIxHGbwKEDcTo7-ZajAny8D0X2ioUGlOWkGrw,1641
28
+ tpc_plugin_validator/rule_sets/rule_set.py,sha256=tdSj0OkuLTjFJZT5CxkoyApH6ZDWoc5M42SNRiXr2uw,5728
29
+ tpc_plugin_validator/rule_sets/section_rule_set.py,sha256=3h8F9nI1s88hKfORN1XXUaG11ML9l9ytPx6P-6KpRgw,1943
30
+ tpc_plugin_validator/rule_sets/states_section_rule_set.py,sha256=VMznvxqvgbYnngyXAr7nIpyeFTVvw5Fu774UhS4T8QI,5550
31
+ tpc_plugin_validator/rule_sets/transitions_section_rule_set.py,sha256=cnVz2yfoj9FgebfQMK68L4atO27_D3LS9zON_6PM4zQ,6855
32
+ tpc_plugin_validator/utilities/__init__.py,sha256=eIdZea9EkshGJmN09wsnUVm661sTy2UH83h4kSfufgQ,69
33
+ tpc_plugin_validator/utilities/exceptions.py,sha256=tc1hXH1XXm1ZdLpaeeFrR2QYLslg7hoQjctPS7cZETY,227
34
+ tpc_plugin_validator/utilities/severity.py,sha256=5Yh3gnbDc5kXX5o0bbfMTKrFpKxpfjhwJFKeyk5vTas,233
35
+ tpc_plugin_validator/utilities/types.py,sha256=mfYtcTtj5K4MJP6vBw7bdlOhFDBJ26TmbZfQF419mjI,1713
36
+ tpc_plugin_validator/utilities/validation_result.py,sha256=9qGpKdb9J5KNkCNRmLnaxIiebPOqtlZohBWtKbLqM_k,309
37
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/METADATA,sha256=xGMBcs_RLokC749DzqRNjYRku1lfkMcUjlE1nV9mem4,2209
38
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/entry_points.txt,sha256=77dSsMZKHYjvbczAI8SCO-zNtS3F4hQWO7fFWEQ7XRE,65
40
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/top_level.txt,sha256=vxogCWT2oDGffT5_IEB3TcbkXU8h30V9KO_rWxHBG0U,21
41
+ cyberark_tpc_plugin_validator-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tpc-validator = tpc_plugin_validator.main:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 (Peter McDonald)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ tpc_plugin_validator
@@ -0,0 +1 @@
1
+ """Standard blank __init__ file for the tpc_plugin_validator package."""
@@ -0,0 +1 @@
1
+ # Standard blank __init__ file for the tpc_plugin_validator package.
@@ -0,0 +1,221 @@
1
+ import re
2
+
3
+ from tpc_plugin_validator.lexer.tokens.assignment import Assignment
4
+ from tpc_plugin_validator.lexer.tokens.comment import Comment
5
+ from tpc_plugin_validator.lexer.tokens.cpm_parameter_validation import (
6
+ CPMParameterValidation,
7
+ )
8
+ from tpc_plugin_validator.lexer.tokens.fail_state import FailState
9
+ from tpc_plugin_validator.lexer.tokens.section_header import SectionHeader
10
+ from tpc_plugin_validator.lexer.tokens.transition import Transition
11
+ from tpc_plugin_validator.lexer.utilities.regex import (
12
+ ASSIGNMENT,
13
+ COMMENT,
14
+ CPM_PARAMETER_VALIDATION,
15
+ FAIL_STATE,
16
+ SECTION_HEADER,
17
+ TRANSITION,
18
+ )
19
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
20
+ from tpc_plugin_validator.lexer.utilities.types import ALL_TOKEN_TYPES, TokenSpecs
21
+ from tpc_plugin_validator.utilities.exceptions import LexerException
22
+
23
+
24
+ class Lexer(object):
25
+ """Object to handle processing the ini files."""
26
+
27
+ __slots__ = (
28
+ "_parsed_data",
29
+ "_source",
30
+ "_token_specs",
31
+ )
32
+
33
+ def __init__(self, source: str) -> None:
34
+ """Standard init for the Lexer object."""
35
+
36
+ self._parsed_data: list[
37
+ tuple[
38
+ TokenName,
39
+ ALL_TOKEN_TYPES,
40
+ ]
41
+ ] = []
42
+ self._source: str = source
43
+ self._token_specs: list[TokenSpecs] = [
44
+ {
45
+ "pattern": re.compile(ASSIGNMENT, re.IGNORECASE),
46
+ "token_name": TokenName.ASSIGNMENT,
47
+ "processor_method": "_process_assignment",
48
+ },
49
+ {
50
+ "pattern": re.compile(COMMENT, re.IGNORECASE),
51
+ "token_name": TokenName.COMMENT,
52
+ "processor_method": "_process_comment",
53
+ },
54
+ {
55
+ "pattern": re.compile(CPM_PARAMETER_VALIDATION, re.IGNORECASE),
56
+ "token_name": TokenName.CPM_PARAMETER_VALIDATION,
57
+ "processor_method": "_process_cpm_parameter_validation",
58
+ },
59
+ {
60
+ "pattern": re.compile(FAIL_STATE, re.IGNORECASE),
61
+ "token_name": TokenName.FAIL_STATE,
62
+ "processor_method": "_process_fail_state",
63
+ },
64
+ {
65
+ "pattern": re.compile(SECTION_HEADER, re.IGNORECASE),
66
+ "token_name": TokenName.SECTION_HEADER,
67
+ "processor_method": "_process_section_header",
68
+ },
69
+ {
70
+ "pattern": re.compile(TRANSITION, re.IGNORECASE),
71
+ "token_name": TokenName.TRANSITION,
72
+ "processor_method": "_process_transitions",
73
+ },
74
+ ]
75
+
76
+ def process(self) -> None:
77
+ """
78
+ Process the content of the file line by line.
79
+
80
+ :raises LexerException: If the line is not valid.
81
+ """
82
+
83
+ if self._parsed_data:
84
+ # Returning as we have parsed the data already.
85
+ return
86
+
87
+ for line_number, line in enumerate(self._source.splitlines(), start=1):
88
+ for token_spec in self._token_specs:
89
+ if match := token_spec["pattern"].match(line):
90
+ getattr(self, token_spec["processor_method"])(match=match, line_number=line_number)
91
+ break
92
+ else:
93
+ if line.strip():
94
+ raise LexerException(f'Unable to parse "{line}" on line {line_number}')
95
+
96
+ def _process_assignment(self, match: re.Match, line_number: int) -> None:
97
+ """
98
+ Process a variable assignment line
99
+
100
+ :param match: Regex match of the assignment.
101
+ """
102
+ name: str = str(match["name"]).strip()
103
+ equals = str(match["equals"]).strip() if match.groupdict().get("equals", None) else None
104
+ assigned_stripped = str(match["value"]).strip() if match.groupdict().get("value", None) else None
105
+ assigned = assigned_stripped or None
106
+ self._parsed_data.append(
107
+ (
108
+ TokenName.ASSIGNMENT,
109
+ Assignment(
110
+ name=name,
111
+ equals=equals,
112
+ assigned=assigned,
113
+ line_number=line_number,
114
+ ),
115
+ )
116
+ )
117
+
118
+ def _process_comment(self, match: re.Match, line_number: int) -> None:
119
+ """
120
+ Process the provided comment.
121
+
122
+ :param match: Regex match of the comment.
123
+ """
124
+ self._parsed_data.append(
125
+ (
126
+ TokenName.COMMENT,
127
+ Comment(
128
+ content=str(match["comment"]).strip(),
129
+ line_number=line_number,
130
+ ),
131
+ )
132
+ )
133
+
134
+ def _process_cpm_parameter_validation(self, match: re.Match, line_number: int) -> None:
135
+ """
136
+ Process the provided parameter validation.
137
+
138
+ :param match: Regex match of the parameter validation.
139
+ """
140
+ allow_characters: str | None = None
141
+ if match["allowcharacters"]:
142
+ allow_characters = str(match["allowcharacters"]).strip()
143
+
144
+ self._parsed_data.append(
145
+ (
146
+ TokenName.CPM_PARAMETER_VALIDATION,
147
+ CPMParameterValidation(
148
+ name=str(match["name"]),
149
+ source=str(match["source"]),
150
+ mandatory=str(match["mandatory"]),
151
+ allow_characters=allow_characters,
152
+ line_number=line_number,
153
+ ),
154
+ )
155
+ )
156
+
157
+ def _process_fail_state(self, match: re.Match, line_number: int) -> None:
158
+ """
159
+ Process the provided fail state .
160
+
161
+ :param match: Regex match of the fail state.
162
+ """
163
+ self._parsed_data.append(
164
+ (
165
+ TokenName.FAIL_STATE,
166
+ FailState(
167
+ name=str(match["name"]).strip(),
168
+ message=str(match["message"]).strip(),
169
+ code=int(match["code"]),
170
+ line_number=line_number,
171
+ ),
172
+ )
173
+ )
174
+
175
+ def _process_section_header(self, match: re.Match, line_number: int) -> None:
176
+ """
177
+ Process the provided section header.
178
+
179
+ :param match: Regex match of the section header.
180
+ """
181
+ self._parsed_data.append(
182
+ (
183
+ TokenName.SECTION_HEADER,
184
+ SectionHeader(
185
+ name=str(match["name"].strip()),
186
+ line_number=line_number,
187
+ ),
188
+ )
189
+ )
190
+
191
+ def _process_transitions(self, match: re.Match, line_number: int) -> None:
192
+ """
193
+ Process the provided transitions.
194
+
195
+ :param match: Regex match of the transitions.
196
+ """
197
+ self._parsed_data.append(
198
+ (
199
+ TokenName.TRANSITION,
200
+ Transition(
201
+ current_state=str(match["current"]).strip(),
202
+ condition=str(match["condition"]).strip(),
203
+ next_state=str(match["next"]).strip(),
204
+ line_number=line_number,
205
+ ),
206
+ )
207
+ )
208
+
209
+ @property
210
+ def tokens(
211
+ self,
212
+ ) -> list[
213
+ tuple[
214
+ TokenName,
215
+ ALL_TOKEN_TYPES,
216
+ ]
217
+ ]:
218
+ """A list of tokens found by the lexer."""
219
+ if not self._parsed_data:
220
+ self.process()
221
+ return self._parsed_data
@@ -0,0 +1 @@
1
+ """Standard blank __init__ file for the tpc_plugin_validator package."""
@@ -0,0 +1,16 @@
1
+ """Class to hold the assignment token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Assignment(object):
10
+ """Dataclass to hold variable assignment details."""
11
+
12
+ line_number: int
13
+ name: str
14
+ equals: str | None = None
15
+ assigned: str | None = None
16
+ token_name: str = TokenName.ASSIGNMENT.value
@@ -0,0 +1,14 @@
1
+ """Class to hold the comment token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Comment(object):
10
+ """Dataclass to hold a comment."""
11
+
12
+ line_number: int
13
+ content: str
14
+ token_name: str = TokenName.COMMENT.value
@@ -0,0 +1,17 @@
1
+ """Class to hold the parameter validation token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class CPMParameterValidation(object):
10
+ """Dataclass to hold variable cpm parameter validation details."""
11
+
12
+ line_number: int
13
+ name: str
14
+ source: str
15
+ mandatory: str
16
+ allow_characters: str | None = None
17
+ token_name: str = TokenName.CPM_PARAMETER_VALIDATION.value
@@ -0,0 +1,16 @@
1
+ """Class to hold the fail state token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class FailState(object):
10
+ """Dataclass to hold a fail state."""
11
+
12
+ line_number: int
13
+ name: str
14
+ message: str
15
+ code: int
16
+ token_name: str = TokenName.FAIL_STATE.value
@@ -0,0 +1,14 @@
1
+ """Class to hold the section header token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class SectionHeader(object):
10
+ """Dataclass to hold a section header name."""
11
+
12
+ line_number: int
13
+ name: str
14
+ token_name: str = TokenName.SECTION_HEADER.value
@@ -0,0 +1,16 @@
1
+ """Class to hold the state transition token."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Transition(object):
10
+ """Dataclass to hold state transitions."""
11
+
12
+ line_number: int
13
+ current_state: str
14
+ condition: str
15
+ next_state: str
16
+ token_name: str = TokenName.TRANSITION.value
@@ -0,0 +1 @@
1
+ """Standard blank __init__ file for the tpc_plugin_validator package."""
@@ -0,0 +1,10 @@
1
+ """List of regex the lexer uses."""
2
+
3
+ ASSIGNMENT = (
4
+ r"^(?:[\s]*)(?P<name>[\w]+)(?:(?:[\s]*)(?P<equals>=)(?:(?:[\s]*)(?P<value>(?:(?!\s*fail\s*\().)+))?)?(?:[\s]*)$"
5
+ )
6
+ COMMENT = r"^(?:[\s]*)(?P<comment>(?:[#;]+)(?:.*))(?:[\s]*)$"
7
+ CPM_PARAMETER_VALIDATION = r"^(?:[\s]*)(?P<name>[\w\\]+)(?:(?:[\s]*,[\s]*)(?:source)(?:[\s]*)=(?:[\s]*)(?P<source>[^, ]*))(?:(?:[\s]*,[\s]*)(?:mandatory)(?:[\s]*)=(?:[\s]*)(?P<mandatory>[^,]*))?(?:(?:[\s]*,[\s]*)(?:allowcharacters)(?:[\s]*)=(?:[\s]*)(?P<allowcharacters>.*))?$"
8
+ FAIL_STATE = r"^(?:[\s]*)(?P<name>[\w]+)(?:[\s]*)=(?:[\s]*)(?:[\s]*)(?:fail)(?:[\s]*)\((?:[\s]*)(?P<message>.*)(?:[\s])?,(?:[\s]*)(?P<code>[0-9]+)\)(?:[\s]*)$"
9
+ SECTION_HEADER = r"^(?:[\s]*)\[(?P<name>[\w]+(?:[\s]+[\w]+)*)](?:[\s]*)$"
10
+ TRANSITION = r"^(?:[\s]*)(?P<current>[\w]+)(?:[\s]*,[\s]*)(?P<condition>[\w]+)(?:[\s]*,[\s]*)(?P<next>[\w]+)(?:[\s]*)$"
@@ -0,0 +1,14 @@
1
+ """Enum to hold the allowed token names."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class TokenName(Enum):
7
+ """CLass to hold the token name."""
8
+
9
+ ASSIGNMENT = "Assignment"
10
+ COMMENT = "Comment"
11
+ FAIL_STATE = "Fail State"
12
+ CPM_PARAMETER_VALIDATION = "CPM Parameter Validation"
13
+ SECTION_HEADER = "Section Header"
14
+ TRANSITION = "Transition"
@@ -0,0 +1,22 @@
1
+ """Module for aggregating all token types used in the lexer."""
2
+
3
+ from typing import TypedDict
4
+ import re
5
+
6
+ from tpc_plugin_validator.lexer.tokens.assignment import Assignment
7
+ from tpc_plugin_validator.lexer.tokens.comment import Comment
8
+ from tpc_plugin_validator.lexer.tokens.cpm_parameter_validation import (
9
+ CPMParameterValidation,
10
+ )
11
+ from tpc_plugin_validator.lexer.tokens.fail_state import FailState
12
+ from tpc_plugin_validator.lexer.tokens.section_header import SectionHeader
13
+ from tpc_plugin_validator.lexer.tokens.transition import Transition
14
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
15
+
16
+ ALL_TOKEN_TYPES = Assignment | Comment | FailState | CPMParameterValidation | SectionHeader | Transition
17
+
18
+
19
+ class TokenSpecs(TypedDict):
20
+ pattern: re.Pattern
21
+ token_name: TokenName
22
+ processor_method: str
@@ -0,0 +1,41 @@
1
+ """Entry point for the TPC Plugin Validator module."""
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+
7
+ from tpc_plugin_validator.parser.parser import Parser
8
+ from tpc_plugin_validator.validator import Validator
9
+
10
+
11
+ def main() -> None:
12
+ """Main entry point for the TPC Plugin Validator module."""
13
+ arg_parse = argparse.ArgumentParser(
14
+ prog="CyberArk TPC Plugin Validator",
15
+ description="Validate the provided TPC process and prompts file.",
16
+ )
17
+ arg_parse.add_argument("process_file", type=str, help="Path to the process file to validate")
18
+ arg_parse.add_argument("prompts_file", type=str, help="Path to the prompts file to validate")
19
+ args = arg_parse.parse_args()
20
+
21
+ if not os.path.isfile(args.process_file):
22
+ arg_parse.error(f'The process file "{args.process_file}" does not exist or is not accessible.')
23
+
24
+ if not os.path.isfile(args.prompts_file):
25
+ arg_parse.error(f'The prompts file "{args.prompts_file}" does not exist or is not accessible.')
26
+
27
+ with open(args.process_file, "r", encoding="utf-8") as process_handler:
28
+ process_file = process_handler.read()
29
+
30
+ with open(args.prompts_file, "r", encoding="utf-8") as prompts_handler:
31
+ prompts_file = prompts_handler.read()
32
+
33
+ parser = Parser(process_file=process_file, prompts_file=prompts_file)
34
+ validator = Validator(parser=parser, config={})
35
+ validator.validate()
36
+ result = validator.get_violations()
37
+ print(result)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ sys.exit(main())
@@ -0,0 +1 @@
1
+ # Standard blank __init__ file for the tpc_plugin_validator package.
@@ -0,0 +1,91 @@
1
+ """Parser module for reading and processing configuration files."""
2
+
3
+ from tpc_plugin_validator.lexer.lexer import Lexer
4
+ from tpc_plugin_validator.lexer.tokens.section_header import SectionHeader
5
+ from tpc_plugin_validator.lexer.utilities.token_name import TokenName
6
+ from tpc_plugin_validator.lexer.utilities.types import ALL_TOKEN_TYPES
7
+
8
+
9
+ class Parser(object):
10
+ """Object to handle parsing ini files."""
11
+
12
+ __slots__ = (
13
+ "_process_file",
14
+ "_process_file_path",
15
+ "_prompts_file",
16
+ "_prompts_file_path",
17
+ )
18
+
19
+ def __init__(self, process_file: str, prompts_file: str) -> None:
20
+ """
21
+ Initializes the Parser with the given process and prompts files.
22
+
23
+ :param process_file (str): Path to the process configuration file.
24
+ :param prompts_file (str): Path to the prompt configuration file.
25
+ """
26
+
27
+ process_lexer = Lexer(source=process_file)
28
+ self._prepare_process(lexed_process=process_lexer)
29
+
30
+ prompts_lexer = Lexer(source=prompts_file)
31
+ self._prepare_prompts(lexed_prompts=prompts_lexer)
32
+
33
+ def _prepare_process(self, lexed_process: Lexer) -> None:
34
+ """
35
+ Prepare the process file from the lexed result.
36
+
37
+ :param lexed_process: Result of lexing the process file.
38
+ """
39
+ self._process_file = self._process_lex(lexed_file=lexed_process)
40
+
41
+ def _prepare_prompts(self, lexed_prompts: Lexer) -> None:
42
+ """
43
+ Prepare the prompts file from the lexed result.
44
+
45
+ :param lexed_prompts: Result of lexing the prompts file.
46
+ """
47
+ self._prompts_file = self._process_lex(lexed_file=lexed_prompts)
48
+
49
+ @staticmethod
50
+ def _process_lex(lexed_file: Lexer):
51
+ """
52
+ Process a lex and return the results.
53
+
54
+ :param lexed_file: Result of lexing a file.
55
+
56
+ :return: Result of processing the lexed file.
57
+ """
58
+ current_section_name: str = "default"
59
+ section_entries: list[ALL_TOKEN_TYPES,] = []
60
+ sorted_lex = {}
61
+ for lexed_line in lexed_file.tokens:
62
+ if lexed_line[0] == TokenName.SECTION_HEADER:
63
+ sorted_lex[current_section_name] = section_entries
64
+ if type(lexed_line[1]) is SectionHeader:
65
+ current_section_name = lexed_line[1].name
66
+ else:
67
+ # This should never be reached, this is here to satisfy typing.
68
+ current_section_name = "UNKNOWN"
69
+ section_entries = []
70
+ continue
71
+ section_entries.append(lexed_line[1])
72
+ sorted_lex[current_section_name] = section_entries
73
+ return sorted_lex
74
+
75
+ @property
76
+ def process_file(self):
77
+ """
78
+ Returns the parsed process configuration.
79
+
80
+ :return: ConfigParser object containing the process file.
81
+ """
82
+ return self._process_file
83
+
84
+ @property
85
+ def prompts_file(self):
86
+ """
87
+ Returns the parsed prompts file.
88
+
89
+ :return: ConfigParser object containing the prompt file.
90
+ """
91
+ return self._prompts_file
@@ -0,0 +1 @@
1
+ """Standard blank __init__ file for the tpc_plugin_validator package."""