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.
Files changed (53) hide show
  1. appython/__init__.py +12 -0
  2. appython/protector.py +554 -0
  3. appython/service/auth_provider.py +273 -0
  4. appython/service/auth_token_provider.py +45 -0
  5. appython/service/config.py +209 -0
  6. appython/service/payload_builder.py +141 -0
  7. appython/service/request_handler.py +115 -0
  8. appython/service/response_handler.py +78 -0
  9. appython/stats/__init__.py +3 -0
  10. appython/stats/collector.py +90 -0
  11. appython/stats/writer.py +185 -0
  12. appython/utils/codec_helper.py +86 -0
  13. appython/utils/constants.py +246 -0
  14. appython/utils/exceptions.py +141 -0
  15. appython/utils/input_preprocessor.py +325 -0
  16. appython/utils/output_postprocessor.py +99 -0
  17. protegrity_ai_developer_python-1.2.1.dist-info/METADATA +428 -0
  18. protegrity_ai_developer_python-1.2.1.dist-info/RECORD +53 -0
  19. protegrity_ai_developer_python-1.2.1.dist-info/WHEEL +5 -0
  20. protegrity_ai_developer_python-1.2.1.dist-info/entry_points.txt +2 -0
  21. protegrity_ai_developer_python-1.2.1.dist-info/licenses/LICENSE +21 -0
  22. protegrity_ai_developer_python-1.2.1.dist-info/top_level.txt +3 -0
  23. protegrity_developer_python/__init__.py +4 -0
  24. protegrity_developer_python/scan.py +37 -0
  25. protegrity_developer_python/securefind.py +83 -0
  26. protegrity_developer_python/utils/ccn_processing.py +59 -0
  27. protegrity_developer_python/utils/config.py +60 -0
  28. protegrity_developer_python/utils/constants.py +123 -0
  29. protegrity_developer_python/utils/discover.py +49 -0
  30. protegrity_developer_python/utils/logger.py +23 -0
  31. protegrity_developer_python/utils/pii_processing.py +291 -0
  32. protegrity_developer_python/utils/protector.py +23 -0
  33. protegrity_developer_python/utils/semantic_guardrails.py +240 -0
  34. protegrity_developer_python/utils/transform.py +66 -0
  35. pty_migrate/__init__.py +1 -0
  36. pty_migrate/check_cmd.py +871 -0
  37. pty_migrate/cli.py +93 -0
  38. pty_migrate/config.py +127 -0
  39. pty_migrate/create_policy_cmd.py +795 -0
  40. pty_migrate/payloads/__init__.py +51 -0
  41. pty_migrate/payloads/alphabets.json +42 -0
  42. pty_migrate/payloads/dataelements.json +342 -0
  43. pty_migrate/payloads/datastores.json +7 -0
  44. pty_migrate/payloads/deploy_policy_ta.json +1 -0
  45. pty_migrate/payloads/masks.json +18 -0
  46. pty_migrate/payloads/members.json +62 -0
  47. pty_migrate/payloads/policies.json +13 -0
  48. pty_migrate/payloads/roles.json +32 -0
  49. pty_migrate/payloads/rules.json +1639 -0
  50. pty_migrate/payloads/sources.json +10 -0
  51. pty_migrate/payloads/trusted_apps.json +8 -0
  52. pty_migrate/ppc_client.py +371 -0
  53. 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 != ""