HumboldtJoker commited on
Commit
4a7cf3e
·
verified ·
1 Parent(s): 5f2247e

Remove nested duplicate: scaffold/scaffold/discipline_gate.py

Browse files
Files changed (1) hide show
  1. scaffold/scaffold/discipline_gate.py +0 -175
scaffold/scaffold/discipline_gate.py DELETED
@@ -1,175 +0,0 @@
1
- """Rivet Discipline Gate — pre-flight check on every suggestion.
2
-
3
- Before any code suggestion reaches the user, it passes through this gate.
4
- The gate checks for dangerous patterns, flags security implications, and
5
- assigns a confidence level. If a suggestion fails the gate, it's blocked
6
- or annotated with warnings.
7
- """
8
-
9
- import re
10
- from dataclasses import dataclass, field
11
- from enum import Enum
12
-
13
-
14
- class Confidence(str, Enum):
15
- HIGH = "HIGH" # Traced the full code path
16
- MEDIUM = "MEDIUM" # Read the code but not run it
17
- LOW = "LOW" # Reasoning from architecture, not source
18
-
19
-
20
- class Severity(str, Enum):
21
- BLOCK = "BLOCK" # Do not suggest this
22
- WARN = "WARN" # Suggest with prominent warning
23
- INFO = "INFO" # Note for awareness
24
-
25
-
26
- @dataclass
27
- class GateResult:
28
- passed: bool = True
29
- flags: list = field(default_factory=list)
30
- confidence: Confidence = Confidence.MEDIUM
31
- requires_review: list = field(default_factory=list)
32
-
33
- def add_flag(self, severity: Severity, message: str):
34
- self.flags.append({"severity": severity.value, "message": message})
35
- if severity == Severity.BLOCK:
36
- self.passed = False
37
-
38
- def format_warnings(self) -> str:
39
- if not self.flags:
40
- return ""
41
- lines = ["\n⚠️ **Discipline Gate Flags:**"]
42
- for f in self.flags:
43
- icon = "🛑" if f["severity"] == "BLOCK" else "⚠️" if f["severity"] == "WARN" else "ℹ️"
44
- lines.append(f" {icon} [{f['severity']}] {f['message']}")
45
- if self.requires_review:
46
- lines.append(f"\n 📋 Requires review from: {', '.join(self.requires_review)}")
47
- lines.append(f"\n 📊 Confidence: {self.confidence.value}")
48
- return "\n".join(lines)
49
-
50
-
51
- # Pattern matchers for dangerous operations
52
- DESTRUCTIVE_MIGRATION_PATTERNS = [
53
- r'\bDROP\s+(TABLE|COLUMN|INDEX|CONSTRAINT)',
54
- r'\bALTER\s+TABLE\s+\w+\s+DROP',
55
- r'\bALTER\s+TABLE\s+\w+\s+ALTER\s+COLUMN\s+\w+\s+TYPE',
56
- r'\bTRUNCATE\s+TABLE',
57
- r'\bDELETE\s+FROM\s+\w+\s*;', # Unqualified DELETE
58
- ]
59
-
60
- AUTH_PATTERNS = [
61
- r'\bJWT_SECRET\b',
62
- r'\bverifyToken\b',
63
- r'\brequireAdmin\b',
64
- r'\brequireModerator\b',
65
- r'\bauth\s*middleware\b',
66
- r'\bsession\s*cookie\b',
67
- r'\brejectIfIneligible\b',
68
- r'\bBearer\b',
69
- ]
70
-
71
- WEBHOOK_BYPASS_PATTERNS = [
72
- r"process\.env\.\w+\s*\|\|\s*['\"]", # env fallback to empty string
73
- r"if\s*\(\s*!secret\s*\)\s*return", # skip on missing secret
74
- r"if\s*\(\s*!.*SECRET.*\)\s*return",
75
- ]
76
-
77
- TRANSACTION_GAPS = [
78
- r'await\s+\w+\.(debit|credit|transfer|purchase|delete)\(', # Multi-step without tx
79
- ]
80
-
81
-
82
- def check_migration_safety(content: str) -> list:
83
- """Check for destructive migration patterns."""
84
- flags = []
85
- for pattern in DESTRUCTIVE_MIGRATION_PATTERNS:
86
- matches = re.findall(pattern, content, re.IGNORECASE)
87
- if matches:
88
- flags.append((Severity.BLOCK,
89
- f"Destructive migration detected: {pattern}. "
90
- f"Staging and prod share the database — additive only."))
91
- return flags
92
-
93
-
94
- def check_auth_impact(content: str) -> list:
95
- """Flag anything touching authentication."""
96
- flags = []
97
- for pattern in AUTH_PATTERNS:
98
- if re.search(pattern, content, re.IGNORECASE):
99
- flags.append((Severity.WARN,
100
- "This touches authentication. Review with security before merging."))
101
- break
102
- return flags
103
-
104
-
105
- def check_webhook_safety(content: str) -> list:
106
- """Check for webhook signature bypass patterns (Audit C2)."""
107
- flags = []
108
- for pattern in WEBHOOK_BYPASS_PATTERNS:
109
- if re.search(pattern, content):
110
- flags.append((Severity.WARN,
111
- "Webhook signature bypass pattern detected (Audit C2). "
112
- "Never skip verification when env var is missing — reject instead."))
113
- break
114
- return flags
115
-
116
-
117
- def check_transaction_safety(content: str) -> list:
118
- """Flag multi-step DB operations that may need transaction wrapping (Audit H3)."""
119
- flags = []
120
- matches = re.findall(r'await\s+\w+\.\w+\(', content)
121
- if len(matches) >= 2:
122
- for pattern in TRANSACTION_GAPS:
123
- if re.search(pattern, content):
124
- flags.append((Severity.WARN,
125
- "Multi-step DB operation detected. Ensure these are wrapped "
126
- "in a single transaction (Audit H3: gem debit without tx protection)."))
127
- break
128
- return flags
129
-
130
-
131
- def run_gate(suggestion: str, context: str = "") -> GateResult:
132
- """Run the full discipline gate on a suggestion.
133
-
134
- Args:
135
- suggestion: The code/text being suggested to the user
136
- context: Optional surrounding context (the question, file being edited)
137
-
138
- Returns:
139
- GateResult with pass/fail, flags, and confidence
140
- """
141
- result = GateResult()
142
- full_content = f"{context}\n{suggestion}"
143
-
144
- # Run all checks
145
- for severity, message in check_migration_safety(full_content):
146
- result.add_flag(severity, message)
147
-
148
- for severity, message in check_auth_impact(full_content):
149
- result.add_flag(severity, message)
150
- result.requires_review.append("security")
151
-
152
- for severity, message in check_webhook_safety(full_content):
153
- result.add_flag(severity, message)
154
- result.requires_review.append("security")
155
-
156
- for severity, message in check_transaction_safety(full_content):
157
- result.add_flag(severity, message)
158
-
159
- return result
160
-
161
-
162
- if __name__ == "__main__":
163
- # Quick test
164
- test_migration = "ALTER TABLE students DROP COLUMN legacy_score;"
165
- result = run_gate(test_migration)
166
- print(f"Migration test: passed={result.passed}")
167
- print(result.format_warnings())
168
-
169
- test_webhook = """
170
- const secret = process.env.STRIPE_SECRET || ''
171
- if (!secret) return next()
172
- """
173
- result = run_gate(test_webhook)
174
- print(f"\nWebhook test: passed={result.passed}")
175
- print(result.format_warnings())