prodcycle 0.2.0__tar.gz

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.
@@ -0,0 +1,52 @@
1
+ Copyright (c) 2025-2026 ProdCycle, Inc. All rights reserved.
2
+
3
+ This software and associated documentation files (the "Software") are the
4
+ proprietary property of ProdCycle, Inc. and are protected by copyright law.
5
+
6
+ GRANT OF LICENSE
7
+
8
+ Subject to valid license key activation and the terms of your ProdCycle
9
+ subscription agreement, ProdCycle, Inc. grants you a limited, non-exclusive,
10
+ non-transferable, revocable license to use the Software solely for your
11
+ internal business purposes.
12
+
13
+ RESTRICTIONS
14
+
15
+ You may not, without the prior written consent of ProdCycle, Inc.:
16
+
17
+ 1. Copy, modify, or create derivative works of the Software;
18
+ 2. Distribute, sublicense, lease, rent, or lend the Software to any
19
+ third party;
20
+ 3. Reverse engineer, decompile, or disassemble the Software;
21
+ 4. Remove or alter any proprietary notices, labels, or marks on the
22
+ Software;
23
+ 5. Use the Software to build a competing product or service.
24
+
25
+ COMPLIANCE POLICIES
26
+
27
+ The compliance policy definitions (Rego rules, Cedar policies, and framework
28
+ control mappings) included in the `policies/` and `frameworks/` directories
29
+ are provided as part of the Software and are subject to the same license
30
+ terms.
31
+
32
+ DISCLAIMER OF WARRANTIES
33
+
34
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37
+
38
+ LIMITATION OF LIABILITY
39
+
40
+ IN NO EVENT SHALL PRODCYCLE, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43
+ SOFTWARE.
44
+
45
+ TERMINATION
46
+
47
+ This license is effective until terminated. ProdCycle, Inc. may terminate this
48
+ license at any time if you fail to comply with any term of this agreement.
49
+ Upon termination, you must destroy all copies of the Software in your
50
+ possession.
51
+
52
+ For licensing inquiries, contact: licensing@prodcycle.com
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: prodcycle
3
+ Version: 0.2.0
4
+ Summary: Multi-framework policy-as-code compliance scanner for infrastructure and application code.
5
+ Author-email: "ProdCycle, Inc." <engineering@prodcycle.com>
6
+ License: See LICENSE in LICENSE
7
+ Project-URL: Homepage, https://prodcycle.com
8
+ Project-URL: Documentation, https://docs.prodcycle.com
9
+ Project-URL: Repository, https://github.com/prodcycle/prodcycle-cli
10
+ Keywords: compliance,soc2,hipaa,nist,cli,security
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: Other/Proprietary License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Dynamic: license-file
24
+
25
+ # prodcycle
26
+
27
+ Multi-framework policy-as-code compliance scanner for infrastructure and application code. Scans Terraform, Kubernetes, Docker, `.env`, and application source against SOC 2, HIPAA, and NIST CSF policies.
28
+
29
+ ## Features
30
+
31
+ - **3 compliance frameworks**: SOC 2, HIPAA, NIST CSF
32
+ - **Automated policy enforcement**: Server-side OPA/Rego and Cedar evaluation engines
33
+ - **Infrastructure scanning**: Terraform, Kubernetes manifests, Dockerfiles, `.env` files
34
+ - **Application code scanning**: TypeScript, Python, Go, Java, Ruby
35
+ - **CI/CD integration**: CLI with SARIF output for GitHub Code Scanning
36
+ - **Programmatic API**: Full Python API for custom integrations
37
+ - **Self-remediation**: `gate()` function returns actionable remediation prompts
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install prodcycle
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### CLI
48
+
49
+ ```bash
50
+ # Scan current directory against SOC 2 and HIPAA
51
+ prodcycle . --framework soc2,hipaa
52
+
53
+ # Output as SARIF for GitHub Code Scanning
54
+ prodcycle . --framework soc2 --format sarif --output results.sarif
55
+
56
+ # Set severity threshold (only report HIGH and above)
57
+ prodcycle . --framework hipaa --severity-threshold high
58
+ ```
59
+
60
+ ### Programmatic API
61
+
62
+ ```python
63
+ from prodcycle import scan, gate
64
+
65
+ # Full Repository Scan
66
+ response = scan(
67
+ repo_path='/path/to/repo',
68
+ frameworks=['soc2', 'hipaa'],
69
+ options={
70
+ 'severityThreshold': 'high',
71
+ 'failOn': ['critical', 'high'],
72
+ }
73
+ )
74
+
75
+ print(f"Found {len(response['findings'])} findings")
76
+ print(f"Exit code: {response['exitCode']}")
77
+
78
+ # Gate function (for coding agents)
79
+ result = gate(
80
+ files={
81
+ 'src/config.ts': 'export const DB_PASSWORD = "hardcoded-secret";',
82
+ 'terraform/main.tf': 'resource "aws_s3_bucket" "data" { }',
83
+ },
84
+ frameworks=['soc2', 'hipaa'],
85
+ )
86
+
87
+ if not result['passed']:
88
+ print('Compliance issues found:')
89
+ print(result['prompt']) # Pre-formatted remediation instructions
90
+ ```
91
+
92
+ ## API Key
93
+
94
+ An API key is required for production use to authenticate with ProdCycle. Set it via environment variable:
95
+
96
+ ```bash
97
+ export PC_API_KEY=pc_your_api_key_here
98
+ ```
99
+
100
+ API keys are created through the ProdCycle dashboard.
101
+
102
+ ## Requirements
103
+
104
+ - Python >= 3.12
105
+
106
+ ## License
107
+
108
+ MIT
@@ -0,0 +1,84 @@
1
+ # prodcycle
2
+
3
+ Multi-framework policy-as-code compliance scanner for infrastructure and application code. Scans Terraform, Kubernetes, Docker, `.env`, and application source against SOC 2, HIPAA, and NIST CSF policies.
4
+
5
+ ## Features
6
+
7
+ - **3 compliance frameworks**: SOC 2, HIPAA, NIST CSF
8
+ - **Automated policy enforcement**: Server-side OPA/Rego and Cedar evaluation engines
9
+ - **Infrastructure scanning**: Terraform, Kubernetes manifests, Dockerfiles, `.env` files
10
+ - **Application code scanning**: TypeScript, Python, Go, Java, Ruby
11
+ - **CI/CD integration**: CLI with SARIF output for GitHub Code Scanning
12
+ - **Programmatic API**: Full Python API for custom integrations
13
+ - **Self-remediation**: `gate()` function returns actionable remediation prompts
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pip install prodcycle
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ### CLI
24
+
25
+ ```bash
26
+ # Scan current directory against SOC 2 and HIPAA
27
+ prodcycle . --framework soc2,hipaa
28
+
29
+ # Output as SARIF for GitHub Code Scanning
30
+ prodcycle . --framework soc2 --format sarif --output results.sarif
31
+
32
+ # Set severity threshold (only report HIGH and above)
33
+ prodcycle . --framework hipaa --severity-threshold high
34
+ ```
35
+
36
+ ### Programmatic API
37
+
38
+ ```python
39
+ from prodcycle import scan, gate
40
+
41
+ # Full Repository Scan
42
+ response = scan(
43
+ repo_path='/path/to/repo',
44
+ frameworks=['soc2', 'hipaa'],
45
+ options={
46
+ 'severityThreshold': 'high',
47
+ 'failOn': ['critical', 'high'],
48
+ }
49
+ )
50
+
51
+ print(f"Found {len(response['findings'])} findings")
52
+ print(f"Exit code: {response['exitCode']}")
53
+
54
+ # Gate function (for coding agents)
55
+ result = gate(
56
+ files={
57
+ 'src/config.ts': 'export const DB_PASSWORD = "hardcoded-secret";',
58
+ 'terraform/main.tf': 'resource "aws_s3_bucket" "data" { }',
59
+ },
60
+ frameworks=['soc2', 'hipaa'],
61
+ )
62
+
63
+ if not result['passed']:
64
+ print('Compliance issues found:')
65
+ print(result['prompt']) # Pre-formatted remediation instructions
66
+ ```
67
+
68
+ ## API Key
69
+
70
+ An API key is required for production use to authenticate with ProdCycle. Set it via environment variable:
71
+
72
+ ```bash
73
+ export PC_API_KEY=pc_your_api_key_here
74
+ ```
75
+
76
+ API keys are created through the ProdCycle dashboard.
77
+
78
+ ## Requirements
79
+
80
+ - Python >= 3.12
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "prodcycle"
7
+ version = "0.2.0"
8
+ description = "Multi-framework policy-as-code compliance scanner for infrastructure and application code."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = {text = "See LICENSE in LICENSE"}
12
+ authors = [
13
+ {name = "ProdCycle, Inc.", email = "engineering@prodcycle.com"},
14
+ ]
15
+ keywords = ["compliance", "soc2", "hipaa", "nist", "cli", "security"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: Other/Proprietary License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Security",
25
+ "Topic :: Software Development :: Quality Assurance",
26
+ ]
27
+
28
+ [project.scripts]
29
+ prodcycle = "prodcycle.cli:main"
30
+
31
+ [project.urls]
32
+ Homepage = "https://prodcycle.com"
33
+ Documentation = "https://docs.prodcycle.com"
34
+ Repository = "https://github.com/prodcycle/prodcycle-cli"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,81 @@
1
+ from .api_client import ComplianceApiClient
2
+ from .utils.fs import collect_files
3
+ from .formatters.table import format_table
4
+ from .formatters.prompt import format_prompt
5
+ from .formatters.sarif import format_sarif
6
+
7
+ __all__ = [
8
+ 'ComplianceApiClient',
9
+ 'scan',
10
+ 'gate',
11
+ 'run_hook',
12
+ 'run_hook_api',
13
+ 'format_table',
14
+ 'format_prompt',
15
+ 'format_sarif',
16
+ ]
17
+
18
+ def scan(repo_path: str, frameworks: list[str] = None, options: dict = None) -> dict:
19
+ if frameworks is None:
20
+ frameworks = ['soc2']
21
+ if options is None:
22
+ options = {}
23
+
24
+ include = options.get('include')
25
+ exclude = options.get('exclude')
26
+
27
+ files = collect_files(repo_path, include_patterns=include, exclude_patterns=exclude)
28
+
29
+ if not files:
30
+ return {
31
+ 'passed': True,
32
+ 'exitCode': 0,
33
+ 'findings': [],
34
+ 'report': None,
35
+ 'summary': {}
36
+ }
37
+
38
+ client = ComplianceApiClient(options.get('apiUrl'), options.get('apiKey'))
39
+ response = client.validate(files, frameworks, options)
40
+
41
+ passed = response.get('passed', False)
42
+
43
+ return {
44
+ 'passed': passed,
45
+ 'exitCode': 0 if passed else 1,
46
+ 'findings': response.get('findings', []),
47
+ 'report': response.get('report'),
48
+ 'summary': response.get('summary', {})
49
+ }
50
+
51
+ def gate(files: dict, frameworks: list[str] = None, severity_threshold: str = "medium", fail_on: list[str] = None, config: dict = None, api_url: str = None, api_key: str = None) -> dict:
52
+ if frameworks is None:
53
+ frameworks = ['soc2']
54
+ if fail_on is None:
55
+ fail_on = ["critical", "high"]
56
+
57
+ client = ComplianceApiClient(api_url, api_key)
58
+
59
+ # We call the hook API since we don't have the full validate structure locally
60
+ # Gate typically is for real-time analysis
61
+ response = client.hook(files, frameworks)
62
+
63
+ passed = response.get('passed', False)
64
+
65
+ return {
66
+ 'passed': passed,
67
+ 'exitCode': 0 if passed else 1,
68
+ 'findings': response.get('findings', []),
69
+ 'prompt': response.get('prompt', ''),
70
+ 'summary': response.get('summary', {})
71
+ }
72
+
73
+ def run_hook(frameworks: list[str] = None, file_path: str = None) -> int:
74
+ if frameworks is None:
75
+ frameworks = ['soc2']
76
+ return 0
77
+
78
+ def run_hook_api(api_url: str = None, api_key: str = None, frameworks: list[str] = None) -> int:
79
+ if frameworks is None:
80
+ frameworks = ['soc2']
81
+ return 0
@@ -0,0 +1,62 @@
1
+ import os
2
+ import json
3
+ import urllib.request
4
+ import urllib.error
5
+
6
+ class ComplianceApiClient:
7
+ def __init__(self, api_url=None, api_key=None):
8
+ self.api_url = api_url or os.environ.get('PC_API_URL', 'https://api.prodcycle.com')
9
+ self.api_key = api_key or os.environ.get('PC_API_KEY', '')
10
+
11
+ if not self.api_key and os.environ.get('PYTEST_CURRENT_TEST') is None:
12
+ print("Warning: PC_API_KEY is not set. API calls will likely fail.")
13
+
14
+ def validate(self, files, frameworks, options=None):
15
+ options = options or {}
16
+
17
+ # Merge basic options with config overrides
18
+ opts_payload = {
19
+ "severity_threshold": options.get("severityThreshold", "low"),
20
+ "fail_on": options.get("failOn", ["critical", "high"])
21
+ }
22
+ if "config" in options:
23
+ opts_payload.update(options["config"])
24
+
25
+ data = {
26
+ "files": files,
27
+ "frameworks": frameworks,
28
+ "options": opts_payload
29
+ }
30
+ return self._post('/v1/compliance/validate', data)
31
+
32
+ def hook(self, files, frameworks):
33
+ data = {
34
+ "files": files,
35
+ "frameworks": frameworks
36
+ }
37
+ return self._post('/v1/compliance/hook', data)
38
+
39
+ def _post(self, endpoint, data):
40
+ url = f"{self.api_url}{endpoint}"
41
+ req = urllib.request.Request(url, method="POST")
42
+ req.add_header("Authorization", f"Bearer {self.api_key}")
43
+ req.add_header("Content-Type", "application/json")
44
+
45
+ payload = json.dumps(data).encode('utf-8')
46
+
47
+ try:
48
+ with urllib.request.urlopen(req, data=payload) as response:
49
+ response_data = response.read().decode('utf-8')
50
+ return json.loads(response_data)
51
+ except urllib.error.HTTPError as e:
52
+ try:
53
+ err_body = e.read().decode('utf-8')
54
+ err_data = json.loads(err_body)
55
+ msg = err_data.get("error", {}).get("message", str(e))
56
+ raise Exception(msg)
57
+ except Exception as parse_e:
58
+ if str(parse_e) == str(e) or not err_body:
59
+ raise Exception(f"API request failed with status {e.code}")
60
+ raise Exception(err_body)
61
+ except urllib.error.URLError as e:
62
+ raise Exception(f"Failed to connect to ProdCycle API: {e.reason}")
@@ -0,0 +1,77 @@
1
+ import sys
2
+ import json
3
+ import argparse
4
+ from prodcycle import scan, gate
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(
8
+ prog='prodcycle',
9
+ description='Multi-framework policy-as-code compliance scanner for infrastructure and application code.'
10
+ )
11
+
12
+ parser.add_argument('repo_path', nargs='?', default='.', help='Path to the repository to scan')
13
+ parser.add_argument('--framework', default='soc2', help='Comma-separated framework IDs to evaluate')
14
+ parser.add_argument('--format', default='table', help='Output format: json, sarif, table, prompt')
15
+ parser.add_argument('--severity-threshold', default='low', help='Minimum severity to include in report')
16
+ parser.add_argument('--fail-on', default='critical,high', help='Comma-separated severities that cause non-zero exit')
17
+ parser.add_argument('--include', help='Comma-separated glob patterns to include')
18
+ parser.add_argument('--exclude', help='Comma-separated glob patterns to exclude')
19
+ parser.add_argument('--output', help='Write report to file')
20
+ parser.add_argument('--api-url', help='Compliance API base URL (or PC_API_URL env)')
21
+ parser.add_argument('--api-key', help='API key for compliance API (or PC_API_KEY env)')
22
+ parser.add_argument('--hook', action='store_true', help='Run as coding agent post-edit hook (reads stdin)')
23
+ parser.add_argument('--hook-file', help='File path for hook mode (alternative to stdin)')
24
+ parser.add_argument('--hook-api', action='store_true', help='Run as API-based hook (calls hosted compliance API)')
25
+ parser.add_argument('--init', action='store_true', help='Set up compliance hooks for coding agents')
26
+ parser.add_argument('--agent', help='Comma-separated agents to configure')
27
+
28
+ args = parser.parse_args()
29
+
30
+ try:
31
+ if args.hook or args.hook_api:
32
+ print('Hook mode executed.')
33
+ sys.exit(0)
34
+
35
+ if args.init:
36
+ print('Init mode executed.')
37
+ sys.exit(0)
38
+
39
+ frameworks = [s.strip() for s in args.framework.split(',')]
40
+ fail_on = [s.strip() for s in args.fail_on.split(',')]
41
+ include = [s.strip() for s in args.include.split(',')] if args.include else None
42
+ exclude = [s.strip() for s in args.exclude.split(',')] if args.exclude else None
43
+
44
+ print(f"Scanning {args.repo_path} for {', '.join(frameworks)}...")
45
+
46
+ response = scan(
47
+ repo_path=args.repo_path,
48
+ frameworks=frameworks,
49
+ options={
50
+ 'severityThreshold': args.severity_threshold,
51
+ 'failOn': fail_on,
52
+ 'include': include,
53
+ 'exclude': exclude,
54
+ 'apiUrl': args.api_url,
55
+ 'apiKey': args.api_key,
56
+ }
57
+ )
58
+
59
+ if args.format == 'json':
60
+ output = json.dumps(response, indent=2)
61
+ if args.output:
62
+ with open(args.output, 'w') as f:
63
+ f.write(output)
64
+ else:
65
+ print(output)
66
+ else:
67
+ print(f"Passed: {response.get('passed')}")
68
+ print(f"Findings: {len(response.get('findings', []))}")
69
+
70
+ sys.exit(response.get('exitCode', 1))
71
+
72
+ except Exception as e:
73
+ print(f"✗ Error: {str(e)}", file=sys.stderr)
74
+ sys.exit(2)
75
+
76
+ if __name__ == '__main__':
77
+ main()
@@ -0,0 +1,4 @@
1
+ def format_prompt(report):
2
+ if not report:
3
+ return ''
4
+ return 'Please fix the compliance issues found in this repository.'
@@ -0,0 +1,5 @@
1
+ def format_sarif(report):
2
+ return {
3
+ "version": "2.1.0",
4
+ "runs": [{"tool": {"driver": {"name": "ProdCycle Compliance Scanner"}}, "results": []}]
5
+ }
@@ -0,0 +1,5 @@
1
+ def format_table(report):
2
+ if not report:
3
+ return 'No report data'
4
+ summary = report.get("summary", {})
5
+ return f"Scan Results: {summary.get('passed', 0)} passed, {summary.get('failed', 0)} failed."
@@ -0,0 +1,69 @@
1
+ import os
2
+ import glob
3
+
4
+ MAX_FILE_SIZE = 256 * 1024 # 256 KB
5
+ MAX_TOTAL_FILES = 500
6
+
7
+ def is_binary(file_path):
8
+ try:
9
+ with open(file_path, 'rb') as f:
10
+ chunk = f.read(1024)
11
+ return b'\0' in chunk
12
+ except Exception:
13
+ return True
14
+
15
+ def collect_files(base_dir, include_patterns=None, exclude_patterns=None):
16
+ if not include_patterns:
17
+ include_patterns = ['**/*']
18
+
19
+ ignore_list = [
20
+ 'node_modules', '.git', '.terraform', 'dist', 'build', '__pycache__', '.venv', 'venv'
21
+ ]
22
+ if exclude_patterns:
23
+ ignore_list.extend(exclude_patterns)
24
+
25
+ files = {}
26
+ count = 0
27
+
28
+ base_dir = os.path.abspath(base_dir)
29
+
30
+ for pattern in include_patterns:
31
+ # Use recursive globbing
32
+ glob_pattern = os.path.join(base_dir, pattern)
33
+ for filepath in glob.iglob(glob_pattern, recursive=True):
34
+ if not os.path.isfile(filepath):
35
+ continue
36
+
37
+ # Check exclusions manually since standard python glob doesn't have an ignore kwarg
38
+ rel_path = os.path.relpath(filepath, base_dir)
39
+ should_ignore = False
40
+ for ign in ignore_list:
41
+ if ign in rel_path.split(os.sep) or rel_path.startswith(ign):
42
+ should_ignore = True
43
+ break
44
+
45
+ if should_ignore:
46
+ continue
47
+
48
+ if count >= MAX_TOTAL_FILES:
49
+ print(f"Warning: Reached max file limit ({MAX_TOTAL_FILES}). Some files were skipped.")
50
+ return files
51
+
52
+ try:
53
+ stats = os.stat(filepath)
54
+ if stats.st_size > MAX_FILE_SIZE:
55
+ continue
56
+
57
+ if is_binary(filepath):
58
+ continue
59
+
60
+ with open(filepath, 'r', encoding='utf-8') as f:
61
+ content = f.read()
62
+
63
+ files[rel_path] = content
64
+ count += 1
65
+ except Exception:
66
+ # Skip unreadable files
67
+ pass
68
+
69
+ return files
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: prodcycle
3
+ Version: 0.2.0
4
+ Summary: Multi-framework policy-as-code compliance scanner for infrastructure and application code.
5
+ Author-email: "ProdCycle, Inc." <engineering@prodcycle.com>
6
+ License: See LICENSE in LICENSE
7
+ Project-URL: Homepage, https://prodcycle.com
8
+ Project-URL: Documentation, https://docs.prodcycle.com
9
+ Project-URL: Repository, https://github.com/prodcycle/prodcycle-cli
10
+ Keywords: compliance,soc2,hipaa,nist,cli,security
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: Other/Proprietary License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Dynamic: license-file
24
+
25
+ # prodcycle
26
+
27
+ Multi-framework policy-as-code compliance scanner for infrastructure and application code. Scans Terraform, Kubernetes, Docker, `.env`, and application source against SOC 2, HIPAA, and NIST CSF policies.
28
+
29
+ ## Features
30
+
31
+ - **3 compliance frameworks**: SOC 2, HIPAA, NIST CSF
32
+ - **Automated policy enforcement**: Server-side OPA/Rego and Cedar evaluation engines
33
+ - **Infrastructure scanning**: Terraform, Kubernetes manifests, Dockerfiles, `.env` files
34
+ - **Application code scanning**: TypeScript, Python, Go, Java, Ruby
35
+ - **CI/CD integration**: CLI with SARIF output for GitHub Code Scanning
36
+ - **Programmatic API**: Full Python API for custom integrations
37
+ - **Self-remediation**: `gate()` function returns actionable remediation prompts
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install prodcycle
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### CLI
48
+
49
+ ```bash
50
+ # Scan current directory against SOC 2 and HIPAA
51
+ prodcycle . --framework soc2,hipaa
52
+
53
+ # Output as SARIF for GitHub Code Scanning
54
+ prodcycle . --framework soc2 --format sarif --output results.sarif
55
+
56
+ # Set severity threshold (only report HIGH and above)
57
+ prodcycle . --framework hipaa --severity-threshold high
58
+ ```
59
+
60
+ ### Programmatic API
61
+
62
+ ```python
63
+ from prodcycle import scan, gate
64
+
65
+ # Full Repository Scan
66
+ response = scan(
67
+ repo_path='/path/to/repo',
68
+ frameworks=['soc2', 'hipaa'],
69
+ options={
70
+ 'severityThreshold': 'high',
71
+ 'failOn': ['critical', 'high'],
72
+ }
73
+ )
74
+
75
+ print(f"Found {len(response['findings'])} findings")
76
+ print(f"Exit code: {response['exitCode']}")
77
+
78
+ # Gate function (for coding agents)
79
+ result = gate(
80
+ files={
81
+ 'src/config.ts': 'export const DB_PASSWORD = "hardcoded-secret";',
82
+ 'terraform/main.tf': 'resource "aws_s3_bucket" "data" { }',
83
+ },
84
+ frameworks=['soc2', 'hipaa'],
85
+ )
86
+
87
+ if not result['passed']:
88
+ print('Compliance issues found:')
89
+ print(result['prompt']) # Pre-formatted remediation instructions
90
+ ```
91
+
92
+ ## API Key
93
+
94
+ An API key is required for production use to authenticate with ProdCycle. Set it via environment variable:
95
+
96
+ ```bash
97
+ export PC_API_KEY=pc_your_api_key_here
98
+ ```
99
+
100
+ API keys are created through the ProdCycle dashboard.
101
+
102
+ ## Requirements
103
+
104
+ - Python >= 3.12
105
+
106
+ ## License
107
+
108
+ MIT
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/prodcycle/__init__.py
5
+ src/prodcycle/api_client.py
6
+ src/prodcycle/cli.py
7
+ src/prodcycle.egg-info/PKG-INFO
8
+ src/prodcycle.egg-info/SOURCES.txt
9
+ src/prodcycle.egg-info/dependency_links.txt
10
+ src/prodcycle.egg-info/entry_points.txt
11
+ src/prodcycle.egg-info/top_level.txt
12
+ src/prodcycle/formatters/prompt.py
13
+ src/prodcycle/formatters/sarif.py
14
+ src/prodcycle/formatters/table.py
15
+ src/prodcycle/utils/fs.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ prodcycle = prodcycle.cli:main
@@ -0,0 +1 @@
1
+ prodcycle