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.
- cyberark_tpc_plugin_validator-0.2.0.dist-info/METADATA +45 -0
- cyberark_tpc_plugin_validator-0.2.0.dist-info/RECORD +41 -0
- cyberark_tpc_plugin_validator-0.2.0.dist-info/WHEEL +5 -0
- cyberark_tpc_plugin_validator-0.2.0.dist-info/entry_points.txt +2 -0
- cyberark_tpc_plugin_validator-0.2.0.dist-info/licenses/LICENSE +21 -0
- cyberark_tpc_plugin_validator-0.2.0.dist-info/top_level.txt +1 -0
- tpc_plugin_validator/__init__.py +1 -0
- tpc_plugin_validator/lexer/__init__.py +1 -0
- tpc_plugin_validator/lexer/lexer.py +221 -0
- tpc_plugin_validator/lexer/tokens/__init__.py +1 -0
- tpc_plugin_validator/lexer/tokens/assignment.py +16 -0
- tpc_plugin_validator/lexer/tokens/comment.py +14 -0
- tpc_plugin_validator/lexer/tokens/cpm_parameter_validation.py +17 -0
- tpc_plugin_validator/lexer/tokens/fail_state.py +16 -0
- tpc_plugin_validator/lexer/tokens/section_header.py +14 -0
- tpc_plugin_validator/lexer/tokens/transition.py +16 -0
- tpc_plugin_validator/lexer/utilities/__init__.py +1 -0
- tpc_plugin_validator/lexer/utilities/regex.py +10 -0
- tpc_plugin_validator/lexer/utilities/token_name.py +14 -0
- tpc_plugin_validator/lexer/utilities/types.py +22 -0
- tpc_plugin_validator/main.py +41 -0
- tpc_plugin_validator/parser/__init__.py +1 -0
- tpc_plugin_validator/parser/parser.py +91 -0
- tpc_plugin_validator/rule_sets/__init__.py +1 -0
- tpc_plugin_validator/rule_sets/conditions_section_rule_set.py +88 -0
- tpc_plugin_validator/rule_sets/cpm_parameters_validation_section_rule_set.py +96 -0
- tpc_plugin_validator/rule_sets/debug_information_section_rule_set.py +154 -0
- tpc_plugin_validator/rule_sets/file_rule_set.py +82 -0
- tpc_plugin_validator/rule_sets/parameters_section_rule_set.py +135 -0
- tpc_plugin_validator/rule_sets/process_file_rule_set.py +47 -0
- tpc_plugin_validator/rule_sets/prompts_file_rule_set.py +40 -0
- tpc_plugin_validator/rule_sets/rule_set.py +157 -0
- tpc_plugin_validator/rule_sets/section_rule_set.py +48 -0
- tpc_plugin_validator/rule_sets/states_section_rule_set.py +128 -0
- tpc_plugin_validator/rule_sets/transitions_section_rule_set.py +158 -0
- tpc_plugin_validator/utilities/__init__.py +1 -0
- tpc_plugin_validator/utilities/exceptions.py +13 -0
- tpc_plugin_validator/utilities/severity.py +11 -0
- tpc_plugin_validator/utilities/types.py +53 -0
- tpc_plugin_validator/utilities/validation_result.py +14 -0
- 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,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."""
|