mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-18 21:49:40 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
---
|
||||
name: building-vulnerability-exception-tracking-system
|
||||
description: Build a vulnerability exception and risk acceptance tracking system with approval workflows, compensating controls documentation, and expiration management.
|
||||
domain: cybersecurity
|
||||
subdomain: vulnerability-management
|
||||
tags: [vulnerability-exception, risk-acceptance, compensating-controls, exception-tracking, vulnerability-management, governance]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Building Vulnerability Exception Tracking System
|
||||
|
||||
## Overview
|
||||
|
||||
A vulnerability exception tracking system manages cases where vulnerabilities cannot be remediated within SLA timelines. It provides structured workflows for requesting exceptions, documenting compensating controls, obtaining risk acceptance approvals, and automatically expiring exceptions when their validity period ends. This ensures organizations maintain visibility into accepted risks while complying with frameworks like PCI DSS, SOC 2, and NIST CSF.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.9+ with `flask`, `sqlalchemy`, `requests`, `jinja2`
|
||||
- PostgreSQL or SQLite database
|
||||
- Email/Slack integration for approval notifications
|
||||
- Vulnerability management platform API (DefectDojo, Qualys, Tenable)
|
||||
|
||||
## Exception Request Workflow
|
||||
|
||||
### Exception Categories
|
||||
| Category | Description | Max Duration | Approver Level |
|
||||
|----------|------------|-------------|----------------|
|
||||
| Remediation Delay | Patch available but deployment blocked | 30 days | Team Lead + Security |
|
||||
| No Fix Available | Vendor has not released a patch | 90 days | Security Director |
|
||||
| Business Critical | System cannot be patched without outage | 60 days | VP Engineering + CISO |
|
||||
| False Positive | Finding is not a real vulnerability | Permanent | Security Analyst |
|
||||
| Compensating Control | Alternative mitigation in place | 180 days | Security Architect |
|
||||
|
||||
### Required Fields for Exception Request
|
||||
|
||||
```python
|
||||
exception_schema = {
|
||||
"cve_id": "CVE-2024-XXXX",
|
||||
"finding_id": "unique-finding-reference",
|
||||
"asset_hostname": "prod-db-01.corp.local",
|
||||
"severity": "high",
|
||||
"cvss_score": 8.1,
|
||||
"category": "remediation_delay",
|
||||
"justification": "Database upgrade required before patch can be applied",
|
||||
"compensating_controls": [
|
||||
"WAF rule blocking exploit pattern deployed",
|
||||
"Network segmentation restricting access to trusted VLANs only",
|
||||
"Enhanced monitoring via Splunk alert for exploitation indicators"
|
||||
],
|
||||
"requested_expiration": "2024-06-15",
|
||||
"requestor_email": "dbadmin@company.com",
|
||||
"approver_emails": ["security-lead@company.com", "ciso@company.com"],
|
||||
"risk_rating": "medium",
|
||||
}
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE vulnerability_exceptions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
cve_id VARCHAR(20) NOT NULL,
|
||||
finding_id VARCHAR(100) NOT NULL,
|
||||
asset_hostname VARCHAR(255),
|
||||
severity VARCHAR(20),
|
||||
cvss_score DECIMAL(3,1),
|
||||
category VARCHAR(50) NOT NULL,
|
||||
justification TEXT NOT NULL,
|
||||
compensating_controls TEXT,
|
||||
status VARCHAR(20) DEFAULT 'pending',
|
||||
requested_by VARCHAR(255) NOT NULL,
|
||||
approved_by VARCHAR(255),
|
||||
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
approved_at TIMESTAMP,
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
expired BOOLEAN DEFAULT FALSE,
|
||||
risk_rating VARCHAR(20),
|
||||
review_notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE exception_audit_log (
|
||||
id SERIAL PRIMARY KEY,
|
||||
exception_id INTEGER REFERENCES vulnerability_exceptions(id),
|
||||
action VARCHAR(50) NOT NULL,
|
||||
actor VARCHAR(255) NOT NULL,
|
||||
details TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_exception_status ON vulnerability_exceptions(status);
|
||||
CREATE INDEX idx_exception_expires ON vulnerability_exceptions(expires_at);
|
||||
CREATE INDEX idx_exception_cve ON vulnerability_exceptions(cve_id);
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### Exception Request API
|
||||
|
||||
```python
|
||||
from flask import Flask, request, jsonify
|
||||
from datetime import datetime, timezone
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/api/exceptions", methods=["POST"])
|
||||
def create_exception():
|
||||
data = request.json
|
||||
required = ["cve_id", "finding_id", "category", "justification", "expires_at", "requestor_email"]
|
||||
for field in required:
|
||||
if field not in data:
|
||||
return jsonify({"error": f"Missing required field: {field}"}), 400
|
||||
|
||||
# Validate expiration does not exceed category maximum
|
||||
max_days = {"remediation_delay": 30, "no_fix": 90, "business_critical": 60,
|
||||
"false_positive": 365, "compensating_control": 180}
|
||||
# Insert into database and notify approvers
|
||||
return jsonify({"status": "pending", "id": "exc-12345"})
|
||||
|
||||
@app.route("/api/exceptions/<exc_id>/approve", methods=["POST"])
|
||||
def approve_exception(exc_id):
|
||||
approver = request.json.get("approver_email")
|
||||
notes = request.json.get("notes", "")
|
||||
# Update status to approved, record approver and timestamp
|
||||
return jsonify({"status": "approved"})
|
||||
|
||||
@app.route("/api/exceptions/<exc_id>/reject", methods=["POST"])
|
||||
def reject_exception(exc_id):
|
||||
reviewer = request.json.get("reviewer_email")
|
||||
reason = request.json.get("reason")
|
||||
# Update status to rejected, record reviewer and reason
|
||||
return jsonify({"status": "rejected"})
|
||||
```
|
||||
|
||||
### Expiration Checker (Daily Cron)
|
||||
|
||||
```bash
|
||||
# Check for expired exceptions daily
|
||||
python3 scripts/process.py --check-expirations
|
||||
|
||||
# Generate monthly exception report
|
||||
python3 scripts/process.py --report --output exception_report.json
|
||||
```
|
||||
|
||||
## Compensating Controls Documentation
|
||||
|
||||
For each exception, compensating controls must address:
|
||||
1. **Detection**: How will exploitation attempts be detected?
|
||||
2. **Prevention**: What barriers reduce exploitation likelihood?
|
||||
3. **Response**: What incident response procedures are in place?
|
||||
4. **Monitoring**: What continuous monitoring ensures controls remain effective?
|
||||
|
||||
## References
|
||||
|
||||
- [NIST SP 800-53 Rev 5 - CA-7 Continuous Monitoring](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final)
|
||||
- [PCI DSS v4.0 Compensating Controls](https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf)
|
||||
- [CIS Controls v8 - Control 7.7](https://www.cisecurity.org/controls/continuous-vulnerability-management)
|
||||
@@ -0,0 +1,55 @@
|
||||
# Vulnerability Exception Request Template
|
||||
|
||||
## Exception Request Form
|
||||
|
||||
### Vulnerability Information
|
||||
- **CVE ID**: CVE-YYYY-NNNNN
|
||||
- **Finding ID**: [Scanner reference number]
|
||||
- **Affected Asset(s)**: [hostname/IP]
|
||||
- **Severity**: [Critical/High/Medium/Low]
|
||||
- **CVSS Score**: [0.0 - 10.0]
|
||||
- **Discovery Date**: [YYYY-MM-DD]
|
||||
- **Original SLA Deadline**: [YYYY-MM-DD]
|
||||
|
||||
### Exception Details
|
||||
- **Category**: [ ] Remediation Delay [ ] No Fix Available [ ] Business Critical [ ] False Positive [ ] Compensating Control
|
||||
- **Requested Expiration Date**: [YYYY-MM-DD]
|
||||
- **Justification**: [Detailed explanation of why remediation cannot be completed within SLA]
|
||||
|
||||
### Compensating Controls
|
||||
1. **Detection Control**: [How will exploitation attempts be detected?]
|
||||
2. **Prevention Control**: [What barriers reduce exploitation likelihood?]
|
||||
3. **Response Procedure**: [What IR procedures are in place for this vulnerability?]
|
||||
4. **Monitoring**: [What ongoing monitoring ensures controls remain effective?]
|
||||
|
||||
### Risk Assessment
|
||||
- **Residual Risk Rating**: [High/Medium/Low]
|
||||
- **Business Impact if Exploited**: [Description]
|
||||
- **Likelihood of Exploitation**: [High/Medium/Low]
|
||||
|
||||
### Requestor
|
||||
- **Name**: [Full name]
|
||||
- **Email**: [email@company.com]
|
||||
- **Department**: [Team/Department]
|
||||
- **Date**: [YYYY-MM-DD]
|
||||
|
||||
---
|
||||
|
||||
## Approval Section (For Approver Use)
|
||||
|
||||
### Decision
|
||||
- [ ] **Approved** - Exception granted with conditions below
|
||||
- [ ] **Rejected** - See rejection reason below
|
||||
- [ ] **More Information Required** - See notes below
|
||||
|
||||
### Conditions (if approved)
|
||||
- [List any additional conditions]
|
||||
|
||||
### Reviewer Notes
|
||||
- [Notes from security review]
|
||||
|
||||
### Approver
|
||||
- **Name**: [Full name]
|
||||
- **Title**: [Job title]
|
||||
- **Date**: [YYYY-MM-DD]
|
||||
- **Signature**: [Digital signature or email confirmation reference]
|
||||
@@ -0,0 +1,34 @@
|
||||
# Standards and References - Vulnerability Exception Tracking
|
||||
|
||||
## Primary Standards
|
||||
|
||||
### NIST SP 800-53 Rev 5 - RA-5(5)
|
||||
- **Title**: Vulnerability Monitoring and Scanning - Privileged Access
|
||||
- **URL**: https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final
|
||||
- **Relevance**: Requires organizations to track and manage vulnerability exceptions with documented risk acceptance
|
||||
|
||||
### PCI DSS v4.0 - Compensating Controls
|
||||
- **URL**: https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf
|
||||
- **Relevance**: Appendix B defines requirements for compensating controls when a PCI requirement cannot be met as stated
|
||||
|
||||
### ISO 27001:2022 - Clause 6.1.3
|
||||
- **Title**: Information Security Risk Treatment
|
||||
- **Relevance**: Risk acceptance must be formally documented with appropriate authority approval
|
||||
|
||||
### CIS Controls v8 - Control 7
|
||||
- **Title**: Continuous Vulnerability Management
|
||||
- **Sub-control 7.7**: Remediate detected vulnerabilities within prescribed timelines; document exceptions with compensating controls
|
||||
|
||||
### SOC 2 - CC3.2
|
||||
- **Title**: Risk Assessment
|
||||
- **Relevance**: Requires evidence of risk acceptance decisions and compensating controls documentation
|
||||
|
||||
## Compliance Requirements for Exceptions
|
||||
|
||||
| Framework | Exception Requirement | Documentation Required |
|
||||
|-----------|----------------------|----------------------|
|
||||
| PCI DSS 4.0 | Compensating Controls Worksheet | Constraint, objective, controls, validation |
|
||||
| SOC 2 Type II | Risk acceptance evidence | Approval chain, justification, review cadence |
|
||||
| HIPAA | Risk analysis documentation | PHI impact, safeguards, timeline |
|
||||
| NIST CSF 2.0 | Risk response decisions | Acceptance criteria, residual risk |
|
||||
| ISO 27001 | Statement of Applicability | Risk owner approval, review schedule |
|
||||
@@ -0,0 +1,47 @@
|
||||
# Workflows - Vulnerability Exception Tracking
|
||||
|
||||
## Workflow 1: Exception Request and Approval
|
||||
|
||||
### Steps
|
||||
1. Asset owner identifies vulnerability that cannot be remediated within SLA
|
||||
2. Owner submits exception request with justification and compensating controls
|
||||
3. System validates request completeness and category-specific fields
|
||||
4. System routes request to appropriate approver based on severity and category
|
||||
5. Approver reviews justification and compensating controls
|
||||
6. Approver approves, rejects, or requests additional information
|
||||
7. If approved, exception is recorded with expiration date
|
||||
8. Vulnerability status updated in scanner/DefectDojo to "exception_approved"
|
||||
9. Audit log entry created with full approval chain
|
||||
|
||||
## Workflow 2: Daily Expiration Check
|
||||
|
||||
### Steps
|
||||
1. Cron job queries all active exceptions with expires_at <= today + 14 days
|
||||
2. For exceptions expiring within 14 days: send renewal reminder to requestor
|
||||
3. For exceptions expiring within 7 days: send urgency reminder with escalation
|
||||
4. For expired exceptions: update status to "expired", revert vulnerability to "open"
|
||||
5. Send expiration notification to asset owner and security team
|
||||
6. Regenerate SLA tracking to include re-opened findings
|
||||
|
||||
## Workflow 3: Quarterly Exception Review
|
||||
|
||||
### Steps
|
||||
1. Generate report of all active exceptions grouped by category and severity
|
||||
2. For each exception, verify compensating controls are still in place
|
||||
3. Review if vendor patch has become available for "no_fix" exceptions
|
||||
4. Re-assess risk rating based on current threat landscape
|
||||
5. Escalate exceptions with changed risk profiles for re-approval
|
||||
6. Update exception records with review notes and new risk ratings
|
||||
7. Submit quarterly report to security governance committee
|
||||
|
||||
## Workflow 4: Compensating Control Validation
|
||||
|
||||
### Steps
|
||||
1. For each active exception, extract listed compensating controls
|
||||
2. Validate each control is still operational:
|
||||
- WAF rules: Query WAF API for rule status
|
||||
- Network segmentation: Verify firewall rules
|
||||
- Monitoring alerts: Confirm SIEM rules are active and triggering
|
||||
3. Flag exceptions where compensating controls have degraded
|
||||
4. Notify exception requestor and security team of control failures
|
||||
5. If controls cannot be restored within 48 hours, revoke exception
|
||||
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Vulnerability Exception Tracking System.
|
||||
|
||||
Manages vulnerability exception requests, approvals, expiration tracking,
|
||||
and compensating controls documentation.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
DB_PATH = os.environ.get("EXCEPTION_DB_PATH", "vulnerability_exceptions.db")
|
||||
|
||||
|
||||
def init_db(db_path=DB_PATH):
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS vulnerability_exceptions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
cve_id TEXT NOT NULL,
|
||||
finding_id TEXT NOT NULL,
|
||||
asset_hostname TEXT,
|
||||
severity TEXT,
|
||||
cvss_score REAL,
|
||||
category TEXT NOT NULL,
|
||||
justification TEXT NOT NULL,
|
||||
compensating_controls TEXT,
|
||||
status TEXT DEFAULT 'pending',
|
||||
requested_by TEXT NOT NULL,
|
||||
approved_by TEXT,
|
||||
requested_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
approved_at TEXT,
|
||||
expires_at TEXT NOT NULL,
|
||||
risk_rating TEXT,
|
||||
review_notes TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS exception_audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
exception_id INTEGER,
|
||||
action TEXT NOT NULL,
|
||||
actor TEXT NOT NULL,
|
||||
details TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (exception_id) REFERENCES vulnerability_exceptions(id)
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
return conn
|
||||
|
||||
|
||||
def create_exception(conn, data):
|
||||
max_days = {
|
||||
"remediation_delay": 30,
|
||||
"no_fix": 90,
|
||||
"business_critical": 60,
|
||||
"false_positive": 365,
|
||||
"compensating_control": 180,
|
||||
}
|
||||
category = data.get("category", "remediation_delay")
|
||||
expires = data.get("expires_at")
|
||||
if expires:
|
||||
exp_date = datetime.fromisoformat(expires)
|
||||
max_exp = datetime.now(timezone.utc) + timedelta(days=max_days.get(category, 30))
|
||||
if exp_date.replace(tzinfo=timezone.utc) > max_exp:
|
||||
print(f"[-] Expiration exceeds maximum {max_days[category]} days for {category}")
|
||||
return None
|
||||
|
||||
cursor = conn.execute(
|
||||
"""INSERT INTO vulnerability_exceptions
|
||||
(cve_id, finding_id, asset_hostname, severity, cvss_score, category,
|
||||
justification, compensating_controls, requested_by, expires_at, risk_rating)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(
|
||||
data["cve_id"], data["finding_id"], data.get("asset_hostname", ""),
|
||||
data.get("severity", ""), data.get("cvss_score", 0),
|
||||
category, data["justification"],
|
||||
json.dumps(data.get("compensating_controls", [])),
|
||||
data["requestor_email"], expires, data.get("risk_rating", "medium"),
|
||||
),
|
||||
)
|
||||
exc_id = cursor.lastrowid
|
||||
conn.execute(
|
||||
"INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)",
|
||||
(exc_id, "created", data["requestor_email"], f"Exception request for {data['cve_id']}"),
|
||||
)
|
||||
conn.commit()
|
||||
print(f"[+] Exception created: ID {exc_id} for {data['cve_id']}")
|
||||
return exc_id
|
||||
|
||||
|
||||
def approve_exception(conn, exc_id, approver_email, notes=""):
|
||||
conn.execute(
|
||||
"""UPDATE vulnerability_exceptions
|
||||
SET status = 'approved', approved_by = ?, approved_at = ?, review_notes = ?
|
||||
WHERE id = ?""",
|
||||
(approver_email, datetime.now(timezone.utc).isoformat(), notes, exc_id),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)",
|
||||
(exc_id, "approved", approver_email, notes),
|
||||
)
|
||||
conn.commit()
|
||||
print(f"[+] Exception {exc_id} approved by {approver_email}")
|
||||
|
||||
|
||||
def reject_exception(conn, exc_id, reviewer_email, reason):
|
||||
conn.execute(
|
||||
"UPDATE vulnerability_exceptions SET status = 'rejected', review_notes = ? WHERE id = ?",
|
||||
(reason, exc_id),
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)",
|
||||
(exc_id, "rejected", reviewer_email, reason),
|
||||
)
|
||||
conn.commit()
|
||||
print(f"[+] Exception {exc_id} rejected by {reviewer_email}: {reason}")
|
||||
|
||||
|
||||
def check_expirations(conn, slack_webhook=None):
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
warn_date = (datetime.now(timezone.utc) + timedelta(days=14)).isoformat()
|
||||
|
||||
expiring_soon = conn.execute(
|
||||
"SELECT * FROM vulnerability_exceptions WHERE status = 'approved' AND expires_at BETWEEN ? AND ?",
|
||||
(now, warn_date),
|
||||
).fetchall()
|
||||
|
||||
expired = conn.execute(
|
||||
"SELECT * FROM vulnerability_exceptions WHERE status = 'approved' AND expires_at < ?",
|
||||
(now,),
|
||||
).fetchall()
|
||||
|
||||
columns = [d[0] for d in conn.execute("SELECT * FROM vulnerability_exceptions LIMIT 0").description]
|
||||
|
||||
for row in expired:
|
||||
record = dict(zip(columns, row))
|
||||
conn.execute("UPDATE vulnerability_exceptions SET status = 'expired' WHERE id = ?", (record["id"],))
|
||||
conn.execute(
|
||||
"INSERT INTO exception_audit_log (exception_id, action, actor, details) VALUES (?, ?, ?, ?)",
|
||||
(record["id"], "expired", "system", f"Exception expired on {record['expires_at']}"),
|
||||
)
|
||||
print(f"[!] Exception {record['id']} ({record['cve_id']}) EXPIRED")
|
||||
|
||||
conn.commit()
|
||||
|
||||
print(f"\n[*] Expiration Check Results:")
|
||||
print(f" Expired: {len(expired)}")
|
||||
print(f" Expiring within 14 days: {len(expiring_soon)}")
|
||||
|
||||
if slack_webhook and (expired or expiring_soon):
|
||||
payload = {
|
||||
"text": f"Vulnerability Exception Alert: {len(expired)} expired, {len(expiring_soon)} expiring soon"
|
||||
}
|
||||
requests.post(slack_webhook, json=payload, timeout=10)
|
||||
|
||||
return {"expired": len(expired), "expiring_soon": len(expiring_soon)}
|
||||
|
||||
|
||||
def generate_report(conn, output_path):
|
||||
report = {
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"summary": {},
|
||||
"exceptions": [],
|
||||
}
|
||||
cursor = conn.execute(
|
||||
"""SELECT status, COUNT(*) as count FROM vulnerability_exceptions GROUP BY status"""
|
||||
)
|
||||
for row in cursor.fetchall():
|
||||
report["summary"][row[0]] = row[1]
|
||||
|
||||
cursor = conn.execute(
|
||||
"SELECT * FROM vulnerability_exceptions ORDER BY CASE status "
|
||||
"WHEN 'expired' THEN 1 WHEN 'pending' THEN 2 WHEN 'approved' THEN 3 ELSE 4 END"
|
||||
)
|
||||
columns = [d[0] for d in cursor.description]
|
||||
for row in cursor.fetchall():
|
||||
report["exceptions"].append(dict(zip(columns, row)))
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
print(f"[+] Exception report written to {output_path}")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Vulnerability Exception Tracking System")
|
||||
parser.add_argument("--db", default=DB_PATH)
|
||||
parser.add_argument("--create", help="JSON file with exception request")
|
||||
parser.add_argument("--approve", type=int, help="Exception ID to approve")
|
||||
parser.add_argument("--reject", type=int, help="Exception ID to reject")
|
||||
parser.add_argument("--approver", help="Approver email")
|
||||
parser.add_argument("--reason", help="Rejection reason")
|
||||
parser.add_argument("--notes", default="", help="Approval notes")
|
||||
parser.add_argument("--check-expirations", action="store_true")
|
||||
parser.add_argument("--report", action="store_true")
|
||||
parser.add_argument("--output", default="exception_report.json")
|
||||
parser.add_argument("--slack-webhook", help="Slack webhook for notifications")
|
||||
args = parser.parse_args()
|
||||
|
||||
conn = init_db(args.db)
|
||||
|
||||
if args.create:
|
||||
with open(args.create, "r") as f:
|
||||
data = json.load(f)
|
||||
create_exception(conn, data)
|
||||
elif args.approve and args.approver:
|
||||
approve_exception(conn, args.approve, args.approver, args.notes)
|
||||
elif args.reject and args.approver and args.reason:
|
||||
reject_exception(conn, args.reject, args.approver, args.reason)
|
||||
elif args.check_expirations:
|
||||
check_expirations(conn, args.slack_webhook)
|
||||
elif args.report:
|
||||
generate_report(conn, args.output)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user