protegrity-ai-developer-python 1.2.1__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.
- appython/__init__.py +12 -0
- appython/protector.py +554 -0
- appython/service/auth_provider.py +273 -0
- appython/service/auth_token_provider.py +45 -0
- appython/service/config.py +209 -0
- appython/service/payload_builder.py +141 -0
- appython/service/request_handler.py +115 -0
- appython/service/response_handler.py +78 -0
- appython/stats/__init__.py +3 -0
- appython/stats/collector.py +90 -0
- appython/stats/writer.py +185 -0
- appython/utils/codec_helper.py +86 -0
- appython/utils/constants.py +246 -0
- appython/utils/exceptions.py +141 -0
- appython/utils/input_preprocessor.py +325 -0
- appython/utils/output_postprocessor.py +99 -0
- protegrity_ai_developer_python-1.2.1.dist-info/METADATA +428 -0
- protegrity_ai_developer_python-1.2.1.dist-info/RECORD +53 -0
- protegrity_ai_developer_python-1.2.1.dist-info/WHEEL +5 -0
- protegrity_ai_developer_python-1.2.1.dist-info/entry_points.txt +2 -0
- protegrity_ai_developer_python-1.2.1.dist-info/licenses/LICENSE +21 -0
- protegrity_ai_developer_python-1.2.1.dist-info/top_level.txt +3 -0
- protegrity_developer_python/__init__.py +4 -0
- protegrity_developer_python/scan.py +37 -0
- protegrity_developer_python/securefind.py +83 -0
- protegrity_developer_python/utils/ccn_processing.py +59 -0
- protegrity_developer_python/utils/config.py +60 -0
- protegrity_developer_python/utils/constants.py +123 -0
- protegrity_developer_python/utils/discover.py +49 -0
- protegrity_developer_python/utils/logger.py +23 -0
- protegrity_developer_python/utils/pii_processing.py +291 -0
- protegrity_developer_python/utils/protector.py +23 -0
- protegrity_developer_python/utils/semantic_guardrails.py +240 -0
- protegrity_developer_python/utils/transform.py +66 -0
- pty_migrate/__init__.py +1 -0
- pty_migrate/check_cmd.py +871 -0
- pty_migrate/cli.py +93 -0
- pty_migrate/config.py +127 -0
- pty_migrate/create_policy_cmd.py +795 -0
- pty_migrate/payloads/__init__.py +51 -0
- pty_migrate/payloads/alphabets.json +42 -0
- pty_migrate/payloads/dataelements.json +342 -0
- pty_migrate/payloads/datastores.json +7 -0
- pty_migrate/payloads/deploy_policy_ta.json +1 -0
- pty_migrate/payloads/masks.json +18 -0
- pty_migrate/payloads/members.json +62 -0
- pty_migrate/payloads/policies.json +13 -0
- pty_migrate/payloads/roles.json +32 -0
- pty_migrate/payloads/rules.json +1639 -0
- pty_migrate/payloads/sources.json +10 -0
- pty_migrate/payloads/trusted_apps.json +8 -0
- pty_migrate/ppc_client.py +371 -0
- pty_migrate/stats_cmd.py +87 -0
pty_migrate/cli.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""CLI entry point for pty-migrate."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from pty_migrate.stats_cmd import run_stats
|
|
8
|
+
from pty_migrate.create_policy_cmd import run_create_policy
|
|
9
|
+
from pty_migrate.check_cmd import run_check
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="pty-migrate",
|
|
15
|
+
description="Protegrity Developer Edition to Team Edition migration tool",
|
|
16
|
+
)
|
|
17
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
18
|
+
|
|
19
|
+
# stats
|
|
20
|
+
stats_parser = subparsers.add_parser("stats", help="View local usage statistics")
|
|
21
|
+
stats_parser.add_argument(
|
|
22
|
+
"--stats-file", help="Path to usage stats JSON (default: ~/.protegrity/usage_stats.json)"
|
|
23
|
+
)
|
|
24
|
+
stats_parser.add_argument("--json", action="store_true", help="Output raw JSON")
|
|
25
|
+
|
|
26
|
+
# create-policy
|
|
27
|
+
cp_parser = subparsers.add_parser("create-policy", help="Create DE policy on PPC (Team Edition)")
|
|
28
|
+
cp_parser.add_argument("--ppc-host",
|
|
29
|
+
help="PPC hostname or IP (or set PTY_PPC_HOST)")
|
|
30
|
+
cp_parser.add_argument("--ppc-user",
|
|
31
|
+
help="PPC username (or set PTY_PPC_USER; default: admin)")
|
|
32
|
+
cp_parser.add_argument("--ppc-password",
|
|
33
|
+
help="PPC admin password. PREFER env var PTY_PPC_PASSWORD "
|
|
34
|
+
"(passing on the command line leaks into shell history); "
|
|
35
|
+
"if neither is set, you'll be prompted interactively.")
|
|
36
|
+
cp_parser.add_argument("--workbench-password",
|
|
37
|
+
help="Password for the auto-provisioned 'workbench' PIM user "
|
|
38
|
+
"(or set PTY_WORKBENCH_PASSWORD). "
|
|
39
|
+
"Defaults to --ppc-password if omitted.")
|
|
40
|
+
cp_parser.add_argument("--ppc-port", type=int, default=None,
|
|
41
|
+
help="PPC port (or set PTY_PPC_PORT; default: 443)")
|
|
42
|
+
cp_parser.add_argument(
|
|
43
|
+
"--stats-file", help="Path to usage stats JSON (default: ~/.protegrity/usage_stats.json)"
|
|
44
|
+
)
|
|
45
|
+
cp_parser.add_argument("--full", action="store_true",
|
|
46
|
+
help="Create full DE policy (ignore stats filter)")
|
|
47
|
+
cp_parser.add_argument("--dry-run", action="store_true",
|
|
48
|
+
help="Show what would be created without calling PPC")
|
|
49
|
+
|
|
50
|
+
# check
|
|
51
|
+
check_parser = subparsers.add_parser("check", help="Pre-flight migration readiness validation")
|
|
52
|
+
check_parser.add_argument("--sdk", choices=["python", "java"], default="python", help="SDK to check")
|
|
53
|
+
check_parser.add_argument("--stats-file", help="Path to usage stats JSON")
|
|
54
|
+
check_parser.add_argument("--ppc-host",
|
|
55
|
+
help="PPC hostname (or set PTY_PPC_HOST). "
|
|
56
|
+
"Required unless --with-protect-fn-test is given.")
|
|
57
|
+
check_parser.add_argument("--ppc-user",
|
|
58
|
+
help="PPC username (or set PTY_PPC_USER; default: workbench)")
|
|
59
|
+
check_parser.add_argument("--ppc-password",
|
|
60
|
+
help="PPC password. PREFER env var PTY_PPC_PASSWORD "
|
|
61
|
+
"(passing on the command line leaks into shell history).")
|
|
62
|
+
check_parser.add_argument("--full", action="store_true",
|
|
63
|
+
help="Verify all bundled Developer Edition data elements on PPC "
|
|
64
|
+
"(default: only DEs found in local usage stats)")
|
|
65
|
+
check_parser.add_argument("--with-protect-fn-test", action="store_true",
|
|
66
|
+
help="Also run protect/unprotect against Cloud Protect. "
|
|
67
|
+
"Use alone (without PPC creds) for a smoke-only check.")
|
|
68
|
+
|
|
69
|
+
args = parser.parse_args()
|
|
70
|
+
|
|
71
|
+
if args.command is None:
|
|
72
|
+
parser.print_help()
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
|
|
75
|
+
# Track whether --ppc-user was explicitly provided (CLI flag, env, or config file)
|
|
76
|
+
if args.command == "create-policy":
|
|
77
|
+
from pty_migrate.config import file_has
|
|
78
|
+
args._ppc_user_explicit = (
|
|
79
|
+
any(a.startswith("--ppc-user") for a in sys.argv)
|
|
80
|
+
or bool(os.getenv("PTY_PPC_USER"))
|
|
81
|
+
or file_has("ppc_user")
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if args.command == "stats":
|
|
85
|
+
return run_stats(args)
|
|
86
|
+
elif args.command == "create-policy":
|
|
87
|
+
return run_create_policy(args)
|
|
88
|
+
elif args.command == "check":
|
|
89
|
+
return run_check(args)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
sys.exit(main() or 0)
|
pty_migrate/config.py
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""Config resolution for pty-migrate CLI.
|
|
2
|
+
|
|
3
|
+
Precedence (highest wins):
|
|
4
|
+
1. CLI flag (explicit on command line)
|
|
5
|
+
2. Environment variable
|
|
6
|
+
3. ~/.protegrity/config.yaml (or $PTY_CONFIG_FILE)
|
|
7
|
+
4. Built-in default
|
|
8
|
+
|
|
9
|
+
Password handling
|
|
10
|
+
-----------------
|
|
11
|
+
Passwords (`ppc_password`, `workbench_password`) are NOT read from the YAML
|
|
12
|
+
file by default. To opt in, the user must set both:
|
|
13
|
+
|
|
14
|
+
allow_secrets_in_file: true
|
|
15
|
+
|
|
16
|
+
at the top of the YAML AND the file must be `chmod 600` (or stricter). If the
|
|
17
|
+
file is group/world-readable the secrets are dropped and a warning is printed
|
|
18
|
+
to stderr, even when the opt-in is set.
|
|
19
|
+
|
|
20
|
+
This mirrors `~/.pgpass` behavior: secrets-at-rest are allowed, but the tool
|
|
21
|
+
refuses to read them from a permissive file.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import os
|
|
25
|
+
import stat
|
|
26
|
+
import sys
|
|
27
|
+
from functools import lru_cache
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
_PASSWORD_KEYS = ("ppc_password", "workbench_password")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _config_path():
|
|
35
|
+
return os.getenv(
|
|
36
|
+
"PTY_CONFIG_FILE", str(Path.home() / ".protegrity" / "config.yaml")
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _file_is_secure(path):
|
|
41
|
+
"""True if `path` is readable only by the owner (mode & 077 == 0)."""
|
|
42
|
+
try:
|
|
43
|
+
mode = os.stat(path).st_mode
|
|
44
|
+
except OSError:
|
|
45
|
+
return False
|
|
46
|
+
if os.name == "nt":
|
|
47
|
+
# Windows doesn't use POSIX bits — assume secure (ACL-based, out of scope).
|
|
48
|
+
return True
|
|
49
|
+
return (mode & (stat.S_IRWXG | stat.S_IRWXO)) == 0
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@lru_cache(maxsize=1)
|
|
53
|
+
def _file_cfg():
|
|
54
|
+
"""Load the SDK config file once per process, applying secret-perm rules.
|
|
55
|
+
|
|
56
|
+
Returns {} on any failure. Password keys are stripped (with a stderr
|
|
57
|
+
warning) unless `allow_secrets_in_file: true` AND the file is `chmod 600`.
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
from appython.service.config import _load_file_config
|
|
61
|
+
cfg = _load_file_config() or {}
|
|
62
|
+
except Exception:
|
|
63
|
+
return {}
|
|
64
|
+
|
|
65
|
+
has_password_keys = any(k in cfg for k in _PASSWORD_KEYS)
|
|
66
|
+
if not has_password_keys:
|
|
67
|
+
return cfg
|
|
68
|
+
|
|
69
|
+
path = _config_path()
|
|
70
|
+
allow = bool(cfg.get("allow_secrets_in_file"))
|
|
71
|
+
if not allow:
|
|
72
|
+
for k in _PASSWORD_KEYS:
|
|
73
|
+
if k in cfg:
|
|
74
|
+
print(
|
|
75
|
+
f" ⚠ Ignoring '{k}' in {path}: set 'allow_secrets_in_file: true' "
|
|
76
|
+
f"to enable file-based passwords.",
|
|
77
|
+
file=sys.stderr,
|
|
78
|
+
)
|
|
79
|
+
cfg.pop(k, None)
|
|
80
|
+
return cfg
|
|
81
|
+
|
|
82
|
+
if not _file_is_secure(path):
|
|
83
|
+
for k in _PASSWORD_KEYS:
|
|
84
|
+
if k in cfg:
|
|
85
|
+
print(
|
|
86
|
+
f" ⚠ Refusing to read '{k}' from {path}: file is group/world readable. "
|
|
87
|
+
f"Run: chmod 600 {path}",
|
|
88
|
+
file=sys.stderr,
|
|
89
|
+
)
|
|
90
|
+
cfg.pop(k, None)
|
|
91
|
+
return cfg
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def resolve(cli_value, env_var, file_key, default=None):
|
|
95
|
+
"""Resolve a single setting using CLI > env > file > default."""
|
|
96
|
+
if cli_value is not None and cli_value != "":
|
|
97
|
+
return cli_value
|
|
98
|
+
env_val = os.getenv(env_var) if env_var else None
|
|
99
|
+
if env_val:
|
|
100
|
+
return env_val
|
|
101
|
+
file_val = _file_cfg().get(file_key) if file_key else None
|
|
102
|
+
if file_val is not None and file_val != "":
|
|
103
|
+
return file_val
|
|
104
|
+
return default
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def resolve_password(cli_value, env_var, file_key):
|
|
108
|
+
"""Resolve a password: CLI > env > file (only if opt-in + chmod 600).
|
|
109
|
+
|
|
110
|
+
Returns a tuple (value, source) where source is one of:
|
|
111
|
+
"cli", "env", "file", None
|
|
112
|
+
"""
|
|
113
|
+
if cli_value:
|
|
114
|
+
return cli_value, "cli"
|
|
115
|
+
env_val = os.getenv(env_var) if env_var else None
|
|
116
|
+
if env_val:
|
|
117
|
+
return env_val, "env"
|
|
118
|
+
file_val = _file_cfg().get(file_key) if file_key else None
|
|
119
|
+
if file_val:
|
|
120
|
+
return file_val, "file"
|
|
121
|
+
return None, None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def file_has(file_key):
|
|
125
|
+
"""True if `file_key` is set in the YAML config (used for 'explicit' detection)."""
|
|
126
|
+
val = _file_cfg().get(file_key)
|
|
127
|
+
return val is not None and val != ""
|