Skip to content

Commit 854c71f

Browse files
authored
Merge pull request #100 from GSA-TTS/develop
Promote Develop to Master
2 parents ea49952 + 425ff3d commit 854c71f

File tree

538 files changed

+68925
-10941
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

538 files changed

+68925
-10941
lines changed

.flake8

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[flake8]
22
max-line-length = 120
3-
extend-ignore = E203, W503, E501, F401, F541, E226, ANN101, ANN204, B009, E712
3+
extend-ignore = E203, W503, E501, F401, F541, E226, ANN101, ANN204, B009, E712, D402
44
exclude =
55
.git,
66
__pycache__,
77
.venv,
88
venv,
99
.env,
1010
env,
11+
test_env,
1112
build,
1213
dist,
1314
.eggs,
@@ -20,7 +21,9 @@ exclude =
2021
violentutf_logs,
2122
security,
2223
.github,
23-
scripts
24+
scripts,
25+
tools/agent_orchestrator,
26+
agent_orchestrator
2427
per-file-ignores =
2528
__init__.py:F401
2629
tests/*:F401,F811,ANN101,ANN401,D202,ANN201,B007,B023,F841,E722,B001,D102,D107,ANN001,ANN002,ANN003,ANN202,C901,D401
@@ -35,7 +38,38 @@ per-file-ignores =
3538
app/api/endpoints/reports.py:C901
3639
app/api/endpoints/security_scans.py:C901
3740
app/api/endpoints/vulnerability_findings.py:C901
41+
app/api/endpoints/vulnerability_taxonomies.py:C901
42+
app/celery/tasks.py:C901
43+
app/core/abac_permissions.py:C901
44+
app/core/audit.py:C901
45+
app/core/authority.py:C901
46+
app/core/cache.py:C901
3847
app/core/decorators/circuit_breaker.py:C901
48+
app/core/decorators/request_signing.py:C901
49+
app/core/decorators/sanitization.py:C901
50+
app/core/decorators/sql_injection.py:C901
51+
app/core/external_services.py:C901
52+
app/core/field_sanitization.py:C901
53+
app/core/input_validation.py:C901
54+
app/core/permissions.py:C901
55+
app/core/request_signing.py:C901
56+
app/core/sql_injection_prevention.py:C901
57+
app/db/init_mfa_policies.py:C901
58+
app/middleware/authentication.py:C901
59+
app/middleware/csrf.py:C901
60+
app/middleware/oauth.py:C901,ANN201,ANN202
61+
app/middleware/rate_limiting.py:C901
62+
app/middleware/request_signing.py:C901
63+
app/models/role.py:C901
64+
app/models/scan.py:C901
65+
app/services/api_key_service.py:C901
66+
app/services/architectural_report_generator.py:C901
67+
app/services/audit_service.py:C901
68+
app/services/mfa_policy_service.py:C901
69+
app/services/rbac_service.py:C901
70+
app/utils/performance_tracker.py:ANN401,D107,D401,E704
71+
fix_test_patterns.py:C901
72+
tools/pre_audit/*:C901,ANN201,ANN202
3973
max-complexity = 10
4074
statistics = True
4175
count = True
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env python3
2+
"""Analyze Bandit security report and determine if check should fail."""
3+
4+
import json
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def main() -> None:
10+
report_file = Path("bandit-report.json")
11+
12+
if not report_file.exists():
13+
print("❌ Bandit report not found")
14+
sys.exit(1)
15+
16+
with open(report_file) as f:
17+
data = json.load(f)
18+
19+
metrics = data.get("metrics", {})
20+
total = metrics.get("_totals", {})
21+
results = data.get("results", [])
22+
23+
# Display metrics
24+
print("=== Bandit Security Scan Results ===")
25+
print(f"Total issues found: {len(results)}")
26+
print(f"Severity breakdown:")
27+
print(f" HIGH: {total.get('SEVERITY.HIGH', 0)}")
28+
print(f" MEDIUM: {total.get('SEVERITY.MEDIUM', 0)}")
29+
print(f" LOW: {total.get('SEVERITY.LOW', 0)}")
30+
print(f"Confidence breakdown:")
31+
print(f" HIGH: {total.get('CONFIDENCE.HIGH', 0)}")
32+
print(f" MEDIUM: {total.get('CONFIDENCE.MEDIUM', 0)}")
33+
print(f" LOW: {total.get('CONFIDENCE.LOW', 0)}")
34+
35+
# Check for high severity issues
36+
high_severity = total.get("SEVERITY.HIGH", 0)
37+
38+
if high_severity > 0:
39+
print(f"\n❌ Found {high_severity} HIGH severity issues:")
40+
for result in results:
41+
if result.get("issue_severity", "").upper() == "HIGH":
42+
print(f" - {result.get('filename')}:{result.get('line_number')}: {result.get('issue_text')}")
43+
print("\nFailing check due to HIGH severity security issues")
44+
sys.exit(1)
45+
else:
46+
print("\n✅ No HIGH severity issues found - check passed")
47+
if len(results) > 0:
48+
print(f"ℹ️ {len(results)} lower severity issues found - review artifact for details")
49+
sys.exit(0)
50+
51+
52+
if __name__ == "__main__":
53+
main()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env python3
2+
"""Analyze Safety vulnerability report and determine if check should fail."""
3+
4+
import json
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def main() -> None:
10+
report_file = Path("safety-report.json")
11+
12+
if not report_file.exists():
13+
print("ℹ️ Safety report not found - skipping vulnerability check")
14+
sys.exit(0)
15+
16+
with open(report_file) as f:
17+
data = json.load(f)
18+
19+
vulnerabilities = data.get("vulnerabilities", [])
20+
21+
print("=== Safety Dependency Check Results ===")
22+
23+
if not vulnerabilities:
24+
print("✅ No known vulnerabilities found")
25+
sys.exit(0)
26+
27+
# Count by severity (Safety uses different format than we expected)
28+
# Adjust based on actual Safety output format
29+
critical = 0
30+
high = 0
31+
medium = 0
32+
low = 0
33+
34+
for vuln in vulnerabilities:
35+
# Safety might use different field names, adjust as needed
36+
severity = str(vuln.get("severity", vuln.get("vulnerability", ""))).lower()
37+
if "critical" in severity:
38+
critical += 1
39+
elif "high" in severity:
40+
high += 1
41+
elif "medium" in severity:
42+
medium += 1
43+
else:
44+
low += 1
45+
46+
print(f"Total vulnerabilities found: {len(vulnerabilities)}")
47+
if critical + high + medium + low == 0:
48+
# If we couldn't categorize, just show total
49+
print(f" Unable to categorize by severity")
50+
else:
51+
print(f" CRITICAL: {critical}")
52+
print(f" HIGH: {high}")
53+
print(f" MEDIUM: {medium}")
54+
print(f" LOW: {low}")
55+
56+
# Show first few vulnerabilities for visibility
57+
print("\nVulnerabilities found:")
58+
for vuln in vulnerabilities[:5]: # Show first 5
59+
pkg = vuln.get("package", vuln.get("package_name", "Unknown"))
60+
desc = vuln.get("vulnerability", vuln.get("advisory", "No description"))
61+
print(f" - {pkg}: {desc[:100]}...")
62+
63+
if len(vulnerabilities) > 5:
64+
print(f" ... and {len(vulnerabilities) - 5} more")
65+
66+
# Only fail on CRITICAL vulnerabilities
67+
if critical > 0:
68+
print(f"\n❌ Found {critical} CRITICAL vulnerabilities - failing check")
69+
sys.exit(1)
70+
else:
71+
print("\n✅ No CRITICAL vulnerabilities found - check passed")
72+
if len(vulnerabilities) > 0:
73+
print(f"ℹ️ Review the uploaded artifact for full vulnerability details")
74+
sys.exit(0)
75+
76+
77+
if __name__ == "__main__":
78+
main()

.github/scripts/audit-organization-repos.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,14 @@ def matches(self, content: str) -> List[Tuple[int, str]]:
9595
class RepoViolation:
9696
"""Represents a violation found in a repository."""
9797

98-
def __init__(self, repo_name: str, file_path: str, line_num: int, line_content: str, pattern: DangerousPattern):
98+
def __init__(
99+
self,
100+
repo_name: str,
101+
file_path: str,
102+
line_num: int,
103+
line_content: str,
104+
pattern: DangerousPattern,
105+
):
99106
self.repo_name = repo_name
100107
self.file_path = file_path
101108
self.line_num = line_num
@@ -167,7 +174,12 @@ def scan_repository(self, repo: Any) -> List[RepoViolation]:
167174
# Check individual files
168175
individual_files = []
169176
for content in contents:
170-
if content.name in ["Makefile", ".travis.yml", "azure-pipelines.yml", "Jenkinsfile"]:
177+
if content.name in [
178+
"Makefile",
179+
".travis.yml",
180+
"azure-pipelines.yml",
181+
"Jenkinsfile",
182+
]:
171183
individual_files.append(content.path)
172184

173185
# Scan all identified files
@@ -242,7 +254,12 @@ def generate_report(self, output_file: str = "audit-report.json") -> Dict[str, A
242254
"""Generate a comprehensive audit report."""
243255

244256
# Organize violations by severity and repository
245-
by_severity: Dict[str, List[RepoViolation]] = {"CRITICAL": [], "HIGH": [], "MEDIUM": [], "LOW": []}
257+
by_severity: Dict[str, List[RepoViolation]] = {
258+
"CRITICAL": [],
259+
"HIGH": [],
260+
"MEDIUM": [],
261+
"LOW": [],
262+
}
246263
by_repo: Dict[str, List[RepoViolation]] = {}
247264

248265
for violation in self.violations:
@@ -272,13 +289,17 @@ def generate_report(self, output_file: str = "audit-report.json") -> Dict[str, A
272289

273290
# Top violating repositories
274291
top_violators = sorted(
275-
[(repo, len(violations)) for repo, violations in by_repo.items()], key=lambda x: x[1], reverse=True
292+
[(repo, len(violations)) for repo, violations in by_repo.items()],
293+
key=lambda x: x[1],
294+
reverse=True,
276295
)[:10]
277296

278297
report = {
279298
"audit_metadata": stats,
280299
"summary": {
281-
"total_repositories_scanned": len(set(v.repo_name for v in self.violations)) if self.violations else 0,
300+
"total_repositories_scanned": (
301+
len(set(v.repo_name for v in self.violations)) if self.violations else 0
302+
),
282303
"violations_by_severity": {k: len(v) for k, v in by_severity.items()},
283304
"top_violating_repositories": [{"repo": repo, "violations": count} for repo, count in top_violators],
284305
},

.github/scripts/ban-test-masking.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,12 @@ def should_check_file(file_path: Path) -> bool:
114114
return True
115115

116116
# Check CI configuration files
117-
ci_files = [".travis.yml", ".circleci/config.yml", "azure-pipelines.yml", "Jenkinsfile"]
117+
ci_files = [
118+
".travis.yml",
119+
".circleci/config.yml",
120+
"azure-pipelines.yml",
121+
"Jenkinsfile",
122+
]
118123
if any(ci_file in path_str for ci_file in ci_files):
119124
return True
120125

.github/scripts/test-workflow-execution.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@ def _test_embedded_code_execution(self, command: str, step_id: str) -> bool:
146146

147147
# Test actual execution in safe mode
148148
exec_result = subprocess.run( # nosec B603, B607 - Safe testing with controlled input
149-
["bash", f.name], capture_output=True, text=True, timeout=30 # Prevent hanging
149+
["bash", f.name],
150+
capture_output=True,
151+
text=True,
152+
timeout=30, # Prevent hanging
150153
)
151154

152155
os.unlink(f.name)

.github/workflows/architectural-compliance.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Set up Python
3434
uses: actions/setup-python@v5
3535
with:
36-
python-version: '3.11'
36+
python-version: '3.12'
3737
cache: 'pip'
3838

3939
- name: Cache Analysis Results
@@ -56,13 +56,13 @@ jobs:
5656
id: scope
5757
run: |
5858
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
59-
echo "mode=incremental" >> $GITHUB_OUTPUT
59+
echo "mode=ci" >> $GITHUB_OUTPUT
6060
echo "base_ref=origin/${{ github.base_ref }}" >> $GITHUB_OUTPUT
6161
elif [[ "${{ inputs.full_analysis }}" == "true" ]]; then
6262
echo "mode=full" >> $GITHUB_OUTPUT
6363
echo "base_ref=HEAD~1" >> $GITHUB_OUTPUT
6464
else
65-
echo "mode=incremental" >> $GITHUB_OUTPUT
65+
echo "mode=ci" >> $GITHUB_OUTPUT
6666
echo "base_ref=HEAD~1" >> $GITHUB_OUTPUT
6767
fi
6868
@@ -194,6 +194,11 @@ jobs:
194194
runs-on: ubuntu-latest
195195
if: github.event_name == 'pull_request'
196196

197+
permissions:
198+
contents: read
199+
issues: write
200+
pull-requests: write
201+
197202
steps:
198203
- name: Add PR Label
199204
uses: actions/github-script@v7

0 commit comments

Comments
 (0)