diff --git a/.gitignore b/.gitignore index ab522878..f4bf8da8 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,17 @@ site/museum/ museum/ updated_results_expanded_story/ updated_results_2/ +gitgalaxy/README gitgalaxy.md +gitgalaxy/core/README core.md +gitgalaxy/physics/README physics.md +gitgalaxy/recorders/README recorder.md +gitgalaxy/security/README security.md +gitgalaxy/standards/README standards.md +gitgalaxy/tools/README tools.md +gitgalaxy/tools/ai_guardrails/README ai.md +gitgalaxy/tools/cobol_to_cobol/README c2c.md +gitgalaxy/tools/cobol_to_java/README c2j.md +gitgalaxy/tools/compliance/README sbom.md +gitgalaxy/tools/network_auditing/README network.md +gitgalaxy/tools/supply_chain_security/README supply_chain.md +gitgalaxy/tools/terabyte_log_scanning/README terabyte.md diff --git a/gitgalaxy/core/network_risk_sensor.py b/gitgalaxy/core/network_risk_sensor.py index 06295ec0..6ce6d6e1 100644 --- a/gitgalaxy/core/network_risk_sensor.py +++ b/gitgalaxy/core/network_risk_sensor.py @@ -275,16 +275,16 @@ def _fallback_map_ecosystem(self, stars: List[Dict[str, Any]]) -> Tuple[List[Dic if "telemetry" not in s: s["telemetry"] = {} s["telemetry"]["network_metrics"] = { - "pagerank_score": None, - "normalized_blast_radius": None, - "betweenness_score": None, - "closeness_score": None, + "pagerank_score": 0.0, + "normalized_blast_radius": 0.0, + "betweenness_score": 0.0, + "closeness_score": 0.0, "in_degree": in_d, "out_degree": out_d, "producer_ratio": round(producer_ratio, 3), "ecosystem_role": ecosystem_role, - "systemic_threat_vector": None, - "is_algorithmic_bottleneck": None + "systemic_threat_vector": [], + "is_algorithmic_bottleneck": False } s["telemetry"]["popularity"] = in_d diff --git a/gitgalaxy/physics/signal_processor.py b/gitgalaxy/physics/signal_processor.py index c717fc2f..96d44bac 100644 --- a/gitgalaxy/physics/signal_processor.py +++ b/gitgalaxy/physics/signal_processor.py @@ -837,13 +837,13 @@ def get_avg(metric_name): # ---> N-DIMENSIONAL AI NETWORK POSTURE <--- if ai_files: # Find the most heavily relied-upon AI node in the graph - ai_files.sort(key=lambda x: x.get("telemetry", {}).get("network_metrics", {}).get("pagerank_score", 0.0), reverse=True) + ai_files.sort(key=lambda x: x.get("telemetry", {}).get("network_metrics", {}).get("pagerank_score") or 0.0, reverse=True) primary_ai_node = ai_files[0] net_mets = primary_ai_node.get("telemetry", {}).get("network_metrics", {}) role = net_mets.get("ecosystem_role", "Unknown") - pr = net_mets.get("normalized_blast_radius", 0.0) - btw = net_mets.get("betweenness_score", 0.0) + pr = net_mets.get("normalized_blast_radius") or 0.0 + btw = net_mets.get("betweenness_score") or 0.0 ai_topology["insights"].append(f"Structural Posture: The primary AI integration acts as a '{role}' within the repository.") @@ -1675,9 +1675,9 @@ def get_cumulative_risk(f): rv = file_data.get("risk_vector", []) p = file_data.get("path", "") - btw = net.get("betweenness_score", 0.0) - close = net.get("closeness_score", 0.0) - pr = net.get("normalized_blast_radius", 0.0) + btw = net.get("betweenness_score") or 0.0 + close = net.get("closeness_score") or 0.0 + pr = net.get("normalized_blast_radius") or 0.0 flux_risk = rv[flux_idx] if flux_idx >= 0 and len(rv) > flux_idx else 0.0 err_risk = rv[err_idx] if err_idx >= 0 and len(rv) > err_idx else 0.0 diff --git a/tests/test_zero_dependency.py b/tests/test_zero_dependency.py new file mode 100644 index 00000000..d6e6c8a2 --- /dev/null +++ b/tests/test_zero_dependency.py @@ -0,0 +1,49 @@ +import unittest +from unittest.mock import patch + +from gitgalaxy.core.network_risk_sensor import NetworkRiskSensor +from gitgalaxy.physics.signal_processor import SignalProcessor + +class TestZeroDependencyMode(unittest.TestCase): + + @patch('gitgalaxy.core.network_risk_sensor.HAS_NETWORKX', False) + def test_fallback_does_not_crash_signal_processor(self): + """ + Simulates a user running GalaxyScope without 'networkx' installed. + Ensures that the None-type fallbacks don't crash Phase 6 Synthesis. + """ + # 1. Initialize the blinded sensor + sensor = NetworkRiskSensor() + + # 2. Create a mock star (file) with some basic AI topology hits to trigger that specific math + mock_stars = [{ + "path": "src/ai_agent.py", + "lang_id": "python", + "coding_loc": 100, + "raw_imports": [], + "hit_vector": [1, 0, 0, 0, 0, 0, 0, 0, 0], # Trigger AI logic + "risk_vector": [0.0] * 18, + "telemetry": {} + }] + + # 3. Force the sensor to use the fallback method + mapped_stars, macro_metrics = sensor.map_ecosystem(mock_stars) + + # 4. Pass the resulting payload into the Signal Processor + processor = SignalProcessor() + + try: + # If the bug exists, this will throw a TypeError due to NoneType math + processor.summarize_galaxy_metrics(mapped_stars, unparsable_files=[]) + processor.generate_forensic_report(mapped_stars) + + # 5. Assert the fallback values populated safely as 0.0 floats + network_metrics = mapped_stars[0]["telemetry"]["network_metrics"] + self.assertEqual(network_metrics["betweenness_score"], 0.0) + self.assertEqual(network_metrics["normalized_blast_radius"], 0.0) + + except TypeError as e: + self.fail(f"Zero-Dependency Mode crashed the Signal Processor! Error: {e}") + +if __name__ == '__main__': + unittest.main() \ No newline at end of file