agentsecure 0.1.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 (78) hide show
  1. agentsecure/__init__.py +4 -0
  2. agentsecure/__main__.py +5 -0
  3. agentsecure/api/__init__.py +1 -0
  4. agentsecure/api/server.py +8 -0
  5. agentsecure/api/services.py +3 -0
  6. agentsecure/cli/__init__.py +2 -0
  7. agentsecure/cli/common.py +116 -0
  8. agentsecure/cli/demo.py +97 -0
  9. agentsecure/cli/main.py +912 -0
  10. agentsecure/cli/policy.py +47 -0
  11. agentsecure/cli/project.py +137 -0
  12. agentsecure/cli/secrets.py +293 -0
  13. agentsecure/cli/settings.py +112 -0
  14. agentsecure/client/__init__.py +1 -0
  15. agentsecure/client/wrappers.py +87 -0
  16. agentsecure/cloud.py +30 -0
  17. agentsecure/core/__init__.py +2 -0
  18. agentsecure/core/capabilities.py +109 -0
  19. agentsecure/core/command_metadata.py +13 -0
  20. agentsecure/core/config.py +173 -0
  21. agentsecure/core/config_profiles.py +192 -0
  22. agentsecure/core/container.py +75 -0
  23. agentsecure/core/key_service.py +140 -0
  24. agentsecure/core/models.py +183 -0
  25. agentsecure/core/policy_mutation.py +127 -0
  26. agentsecure/core/policy_ports.py +61 -0
  27. agentsecure/core/policy_response.py +68 -0
  28. agentsecure/core/policy_validation.py +97 -0
  29. agentsecure/core/product.py +267 -0
  30. agentsecure/core/time.py +38 -0
  31. agentsecure/crypto/__init__.py +2 -0
  32. agentsecure/crypto/cipher.py +57 -0
  33. agentsecure/crypto/key_provider.py +39 -0
  34. agentsecure/daemon/__init__.py +1 -0
  35. agentsecure/daemon/commands.py +8 -0
  36. agentsecure/daemon/policies.py +3 -0
  37. agentsecure/daemon/sessions.py +3 -0
  38. agentsecure/daemon/supervisor.py +3 -0
  39. agentsecure/discovery/__init__.py +2 -0
  40. agentsecure/discovery/dotenv_scanner.py +60 -0
  41. agentsecure/discovery/env_scanner.py +29 -0
  42. agentsecure/discovery/patterns.py +90 -0
  43. agentsecure/discovery/scanner.py +27 -0
  44. agentsecure/discovery/suggestions.py +154 -0
  45. agentsecure/gateway/__init__.py +2 -0
  46. agentsecure/gateway/proxy.py +272 -0
  47. agentsecure/guard/__init__.py +2 -0
  48. agentsecure/guard/command.py +62 -0
  49. agentsecure/guard/network.py +92 -0
  50. agentsecure/guard/sanitizer.py +105 -0
  51. agentsecure/guard/wrappers.py +50 -0
  52. agentsecure/implementations/__init__.py +2 -0
  53. agentsecure/implementations/audit.py +53 -0
  54. agentsecure/implementations/encrypted_secret_store.py +73 -0
  55. agentsecure/implementations/grant_store.py +84 -0
  56. agentsecure/implementations/local_secret_store.py +53 -0
  57. agentsecure/implementations/policy.py +126 -0
  58. agentsecure/implementations/secret_store_factory.py +21 -0
  59. agentsecure/implementations/secrets.py +138 -0
  60. agentsecure/interfaces/__init__.py +2 -0
  61. agentsecure/interfaces/audit.py +11 -0
  62. agentsecure/interfaces/grants.py +23 -0
  63. agentsecure/interfaces/key_store.py +15 -0
  64. agentsecure/interfaces/policy.py +24 -0
  65. agentsecure/interfaces/secrets.py +19 -0
  66. agentsecure/workspace/__init__.py +2 -0
  67. agentsecure/workspace/apply.py +141 -0
  68. agentsecure/workspace/diff.py +104 -0
  69. agentsecure/workspace/materializer.py +112 -0
  70. agentsecure/workspace/rewriter.py +54 -0
  71. agentsecure/workspace/strategies.py +140 -0
  72. agentsecure-0.1.0.dist-info/METADATA +181 -0
  73. agentsecure-0.1.0.dist-info/RECORD +78 -0
  74. agentsecure-0.1.0.dist-info/WHEEL +5 -0
  75. agentsecure-0.1.0.dist-info/entry_points.txt +2 -0
  76. agentsecure-0.1.0.dist-info/licenses/LICENSE +68 -0
  77. agentsecure-0.1.0.dist-info/licenses/NOTICE +4 -0
  78. agentsecure-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,4 @@
1
+ """AgentSecure local-first security runtime."""
2
+
3
+ __version__ = "0.1.0"
4
+
@@ -0,0 +1,5 @@
1
+ from agentsecure.cli.main import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """Community stub package for private/local API integrations."""
@@ -0,0 +1,8 @@
1
+ class LocalApiServer:
2
+ def __init__(self, host, port, services):
3
+ self.host = host
4
+ self.port = port
5
+ self.services = services
6
+
7
+ def serve_forever(self):
8
+ raise RuntimeError("local API server is not included in AgentSecure Community")
@@ -0,0 +1,3 @@
1
+ class ApiServices:
2
+ def __init__(self, *args, **kwargs):
3
+ raise RuntimeError("local API services are not included in AgentSecure Community")
@@ -0,0 +1,2 @@
1
+ """AgentSecure CLI."""
2
+
@@ -0,0 +1,116 @@
1
+ import json
2
+ import os
3
+ import sys
4
+ from typing import List
5
+
6
+ from agentsecure.core.config import JsonConfigWriter
7
+ from agentsecure.core.key_service import KeyManagementError
8
+ from agentsecure.core.product import ProductService
9
+ from agentsecure.discovery.dotenv_scanner import DotenvSecretScanner
10
+ from agentsecure.discovery.env_scanner import EnvironmentSecretScanner
11
+ from agentsecure.discovery.patterns import mask_secret
12
+ from agentsecure.discovery.scanner import CompositeSecretScanner
13
+
14
+
15
+ def scanner() -> CompositeSecretScanner:
16
+ return CompositeSecretScanner(
17
+ [
18
+ EnvironmentSecretScanner(),
19
+ DotenvSecretScanner(os.getcwd()),
20
+ ]
21
+ )
22
+
23
+
24
+ def load_config_data(config_path: str):
25
+ if not os.path.exists(config_path):
26
+ ProductService(config_path, scanner()).init_project()
27
+ with open(config_path, "r") as handle:
28
+ return json.load(handle)
29
+
30
+
31
+ def normalize_policy_path(path: str) -> str:
32
+ return os.path.normpath(path).lstrip(os.sep)
33
+
34
+
35
+ def normalize_domain(domain: str) -> str:
36
+ return domain.strip().lower().rstrip(".")
37
+
38
+
39
+ def print_discovered(discovered) -> None:
40
+ if not discovered:
41
+ print("No likely secrets found.", flush=True)
42
+ return
43
+ print("AgentSecure found possible secrets:", flush=True)
44
+ for index, secret in enumerate(discovered, 1):
45
+ print(
46
+ "[%s] %s from %s provider=%s value=%s"
47
+ % (index, secret.name, secret.source, secret.provider_hint, mask_secret(secret.value)),
48
+ flush=True,
49
+ )
50
+
51
+
52
+ def selected_indexes(value: str, count: int) -> List[int]:
53
+ if value == "all":
54
+ return list(range(count))
55
+ indexes = []
56
+ for part in value.split(","):
57
+ part = part.strip()
58
+ if not part:
59
+ continue
60
+ number = int(part)
61
+ if number < 1 or number > count:
62
+ raise KeyManagementError("selection out of range: %s" % number)
63
+ indexes.append(number - 1)
64
+ return indexes
65
+
66
+
67
+ def update_protected_files(config_path: str, paths: List[str], add: bool) -> int:
68
+ config = load_config_data(config_path)
69
+ files = config.setdefault("files", {})
70
+ protected = list(files.get("protect_write", []))
71
+ if add:
72
+ for path in paths:
73
+ normalized = normalize_policy_path(path)
74
+ if normalized not in protected:
75
+ protected.append(normalized)
76
+ else:
77
+ remove = set(normalize_policy_path(path) for path in paths)
78
+ protected = [path for path in protected if path not in remove]
79
+ files["protect_write"] = protected
80
+ JsonConfigWriter().save(config_path, config)
81
+ print("Protected write paths:")
82
+ for path in protected:
83
+ print(" %s" % path)
84
+ return 0
85
+
86
+
87
+ def update_allowed_domains(config_path: str, domains: List[str], add: bool) -> int:
88
+ config = load_config_data(config_path)
89
+ network = config.setdefault("network", {})
90
+ allowed = list(network.get("allow_domains", []))
91
+ if add:
92
+ for domain in domains:
93
+ normalized = normalize_domain(domain)
94
+ if normalized and normalized not in allowed:
95
+ allowed.append(normalized)
96
+ else:
97
+ remove = set(normalize_domain(domain) for domain in domains)
98
+ allowed = [domain for domain in allowed if domain not in remove]
99
+ network["allow_domains"] = allowed
100
+ JsonConfigWriter().save(config_path, config)
101
+ print("Allowed credential domains:")
102
+ for domain in allowed:
103
+ print(" %s" % domain)
104
+ return 0
105
+
106
+
107
+ def cloud_features_enabled() -> bool:
108
+ return os.environ.get("AGENTSECURE_ENABLE_CLOUD", "").strip() == "1"
109
+
110
+
111
+ def cloud_features_disabled() -> int:
112
+ sys.stderr.write(
113
+ "agentsecure: cloud features are not enabled in community mode "
114
+ "(set AGENTSECURE_ENABLE_CLOUD=1 in private builds)\n"
115
+ )
116
+ return 2
@@ -0,0 +1,97 @@
1
+ import argparse
2
+ import os
3
+ import shutil
4
+ import subprocess
5
+ import tempfile
6
+
7
+ from agentsecure.cli.common import load_config_data, scanner
8
+ from agentsecure.core.config import JsonConfigWriter
9
+ from agentsecure.core.key_service import KeyManagementService
10
+ from agentsecure.core.product import ProductService
11
+ from agentsecure.guard.sanitizer import SecretOutputSanitizer
12
+ from agentsecure.implementations.audit import JsonLineAuditLogger
13
+ from agentsecure.implementations.grant_store import LocalJsonGrantStore
14
+ from agentsecure.implementations.secret_store_factory import encrypted_secret_store_for_config
15
+ from agentsecure.workspace.materializer import make_tree_writable
16
+
17
+
18
+ def run_demo(args: argparse.Namespace) -> int:
19
+ demo_dir = tempfile.mkdtemp(prefix="agentsecure-demo-")
20
+ current = os.getcwd()
21
+ try:
22
+ os.chdir(demo_dir)
23
+ config_path = os.path.join(demo_dir, "agentsecure.json")
24
+ env_path = os.path.join(demo_dir, ".env")
25
+ openai_secret = "sk-demo-local-secret-do-not-use"
26
+ database_secret = "postgres://demo:demo-password@production.example/app"
27
+ with open(env_path, "w") as handle:
28
+ handle.write("OPENAI_API_KEY=%s\n" % openai_secret)
29
+ handle.write("DATABASE_URL_PROD=%s\n" % database_secret)
30
+
31
+ ProductService(config_path, scanner()).init_project(force=True)
32
+ service = KeyManagementService(
33
+ config_path,
34
+ encrypted_secret_store_for_config(config_path),
35
+ LocalJsonGrantStore(os.path.join(demo_dir, ".agentsecure", "grants.json")),
36
+ JsonLineAuditLogger(os.path.join(demo_dir, ".agentsecure", "audit.log")),
37
+ )
38
+ openai_result = service.create_key(
39
+ env_name="OPENAI_API_KEY",
40
+ real_secret=openai_secret,
41
+ provider="openai",
42
+ ttl="2h",
43
+ )
44
+ service.create_key(
45
+ env_name="DATABASE_URL_PROD",
46
+ real_secret=database_secret,
47
+ provider="database",
48
+ ttl="2h",
49
+ )
50
+ config = load_config_data(config_path)
51
+ config.setdefault("env_policy", {})["DATABASE_URL_PROD"] = {
52
+ "mode": "deny",
53
+ "environment": "production",
54
+ "risk": "high",
55
+ "reason": "production database credentials are not exposed to local agents",
56
+ }
57
+ JsonConfigWriter().save(config_path, config)
58
+
59
+ raw_output = _demo_read_dotenv(demo_dir)
60
+ sanitizer = SecretOutputSanitizer.from_config_path(config_path)
61
+ agent_visible = sanitizer.sanitize_text(raw_output)
62
+
63
+ print("AgentSecure community demo (local only)")
64
+ print("Project: %s" % demo_dir)
65
+ print("Command: cat .env")
66
+ print("Decision: mask OPENAI_API_KEY and block DATABASE_URL_PROD")
67
+ print("")
68
+ print("Agent-visible output:")
69
+ print(agent_visible, end="" if agent_visible.endswith("\n") else "\n")
70
+ print("")
71
+ print("Why:")
72
+ print(" OPENAI_API_KEY was replaced with %s" % openai_result["virtual_token"])
73
+ print(" DATABASE_URL_PROD was removed because env_policy sets mode=deny")
74
+ print(" Real secret values stayed local in the demo project")
75
+ print(" No cloud service, billing service, or enterprise policy sync was used")
76
+ if args.keep:
77
+ print("")
78
+ print("Kept demo project: %s" % demo_dir)
79
+ return 0
80
+ finally:
81
+ os.chdir(current)
82
+ if not args.keep:
83
+ make_tree_writable(demo_dir)
84
+ shutil.rmtree(demo_dir, ignore_errors=True)
85
+
86
+
87
+ def _demo_read_dotenv(demo_dir: str) -> str:
88
+ try:
89
+ return subprocess.check_output(
90
+ ["cat", ".env"],
91
+ cwd=demo_dir,
92
+ stderr=subprocess.STDOUT,
93
+ universal_newlines=True,
94
+ )
95
+ except (OSError, subprocess.SubprocessError):
96
+ with open(os.path.join(demo_dir, ".env"), "r") as handle:
97
+ return handle.read()