From 1c6c6879c7b4393e89779481aec7ddaab9b5c608 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 16 Feb 2026 21:56:44 -0700 Subject: [PATCH] Complete Step 492: phase 24b integration --- editor/CMakeLists.txt | 9 ++ editor/src/SecurityPipelineIntegration.h | 61 ++++++++++ editor/tests/step492_test.cpp | 137 +++++++++++++++++++++++ progress.md | 51 +++++++++ 4 files changed, 258 insertions(+) create mode 100644 editor/src/SecurityPipelineIntegration.h create mode 100644 editor/tests/step492_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 67a0b76..173b456 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -3307,4 +3307,13 @@ target_link_libraries(step491_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step492_test tests/step492_test.cpp) +target_include_directories(step492_test PRIVATE src) +target_link_libraries(step492_test PRIVATE + nlohmann_json::nlohmann_json + unofficial::tree-sitter::tree-sitter + tree_sitter_python tree_sitter_cpp tree_sitter_elisp + tree_sitter_javascript tree_sitter_typescript + tree_sitter_java tree_sitter_rust tree_sitter_go) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/SecurityPipelineIntegration.h b/editor/src/SecurityPipelineIntegration.h new file mode 100644 index 0000000..71a8619 --- /dev/null +++ b/editor/src/SecurityPipelineIntegration.h @@ -0,0 +1,61 @@ +#pragma once + +// Step 492: Phase 24b Integration Pipeline +// Composes security-preserving translation, secure defaults, threat modeling, +// and security test skeleton generation into one structured flow. + +#include "SecureByDefaultGenerator.h" +#include "SecurityPreservingTranslation.h" +#include "SecurityTestSkeletonGenerator.h" +#include "ThreatModelIntegration.h" + +#include +#include + +struct SecurityPipelineInput { + std::string sourceLanguage; + std::string targetLanguage; + std::string moduleName; + std::string entityName; + std::vector sourceAnnotations; + ThreatModelInput threatModel; +}; + +struct SecurityPipelineResult { + SecurityTranslationOutput translation; + SecureGenerationOutput secureSqlSnippet; + SecureGenerationOutput secureInputSnippet; + ThreatModelOutput threat; + SecuritySkeletonOutput tests; + std::vector notes; +}; + +class SecurityPipelineIntegration { +public: + static SecurityPipelineResult run(const SecurityPipelineInput& in) { + SecurityPipelineResult out; + out.translation = SecurityPreservingTranslation::translate({ + in.sourceLanguage, in.targetLanguage, in.sourceAnnotations + }); + + out.secureSqlSnippet = SecureByDefaultGenerator::generate({ + in.targetLanguage, SecureSnippetKind::SqlQuery, + "query" + in.entityName, "security-default" + }); + out.secureInputSnippet = SecureByDefaultGenerator::generate({ + in.targetLanguage, SecureSnippetKind::InputHandling, + "handle" + in.entityName + "Input", "security-default" + }); + + out.threat = ThreatModelIntegration::analyze(in.threatModel); + out.tests = SecurityTestSkeletonGenerator::generate({ + in.targetLanguage, in.moduleName, in.entityName, true + }); + + out.notes.push_back("Pipeline executed: translation -> secure generation -> threat model -> test skeletons"); + if (out.translation.hasBlockingReview) { + out.notes.push_back("Translation produced blocking review requirements"); + } + return out; + } +}; diff --git a/editor/tests/step492_test.cpp b/editor/tests/step492_test.cpp new file mode 100644 index 0000000..e3c5225 --- /dev/null +++ b/editor/tests/step492_test.cpp @@ -0,0 +1,137 @@ +// Step 492: Phase 24b Integration + Sprint Summary Tests (8 tests) + +#include "SecurityPipelineIntegration.h" + +#include +#include + +static int passed = 0, failed = 0; +#define TEST(name) { std::cout << " " << #name << "... "; } +#define PASS() { std::cout << "PASS\n"; ++passed; } +#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; } +#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {} + +static SecurityPipelineInput sampleInput() { + SecurityPipelineInput in; + in.sourceLanguage = "python"; + in.targetLanguage = "rust"; + in.moduleName = "api"; + in.entityName = "User"; + in.sourceAnnotations = { + {"@InputValidation", "sanitized"}, + {"@TrustBoundary", "external-api"}, + {"@Auth", "jwt"}, + {"@Encryption", "aes256"} + }; + in.threatModel.moduleName = "api"; + in.threatModel.boundaries = {{"external-api", "high"}, {"database", "medium"}}; + in.threatModel.flows = {{"external-api", "database", true, "sanitized"}}; + return in; +} + +void test_python_to_rust_translation_preserves_security_annotations() { + TEST(python_to_rust_translation_preserves_security_annotations); + auto out = SecurityPipelineIntegration::run(sampleInput()); + CHECK(out.translation.mappings.size() == 4, "annotation count mismatch"); + CHECK(out.translation.preservedCount() == 4, "security annotations not fully preserved"); + PASS(); +} + +void test_generated_sql_and_input_code_use_secure_defaults() { + TEST(generated_sql_and_input_code_use_secure_defaults); + auto out = SecurityPipelineIntegration::run(sampleInput()); + CHECK(out.secureSqlSnippet.code.find(".bind(") != std::string::npos || + out.secureSqlSnippet.code.find("?") != std::string::npos || + out.secureSqlSnippet.code.find("%s") != std::string::npos, + "sql snippet not parameterized"); + bool hasRaw = false; + for (const auto& a : out.secureInputSnippet.annotations) { + if (a == "@InputValidation(raw)") hasRaw = true; + } + CHECK(hasRaw, "input snippet missing raw annotation"); + PASS(); +} + +void test_threat_model_outputs_boundary_diagnostics_when_validation_missing() { + TEST(threat_model_outputs_boundary_diagnostics_when_validation_missing); + auto in = sampleInput(); + in.threatModel.flows = {{"external-api", "database", false, ""}}; + auto out = SecurityPipelineIntegration::run(in); + CHECK(!out.threat.diagnostics.empty(), "expected threat diagnostics"); + CHECK(out.threat.diagnostics[0].code == 1300, "expected E1300"); + PASS(); +} + +void test_security_test_skeletons_generated_with_meaningful_intent() { + TEST(security_test_skeletons_generated_with_meaningful_intent); + auto out = SecurityPipelineIntegration::run(sampleInput()); + CHECK(out.tests.tests.size() >= 5, "expected baseline security tests"); + CHECK(out.tests.tests[0].intentAnnotation.find("@Intent(") == 0, "missing intent annotation"); + PASS(); +} + +void test_translation_blocking_review_propagates_to_pipeline_notes() { + TEST(translation_blocking_review_propagates_to_pipeline_notes); + auto in = sampleInput(); + in.sourceAnnotations.push_back({"@Secrets", "rotation:30d"}); + auto out = SecurityPipelineIntegration::run(in); + CHECK(out.translation.hasBlockingReview, "expected blocking review"); + bool found = false; + for (const auto& n : out.notes) { + if (n.find("blocking review") != std::string::npos) found = true; + } + CHECK(found, "pipeline notes missing blocking-review mention"); + PASS(); +} + +void test_pipeline_notes_include_execution_trace_summary() { + TEST(pipeline_notes_include_execution_trace_summary); + auto out = SecurityPipelineIntegration::run(sampleInput()); + CHECK(!out.notes.empty(), "missing notes"); + CHECK(out.notes[0].find("translation -> secure generation -> threat model -> test skeletons") + != std::string::npos, "missing execution trace summary"); + PASS(); +} + +void test_access_control_and_pen_tests_route_human_in_generated_suite() { + TEST(access_control_and_pen_tests_route_human_in_generated_suite); + auto out = SecurityPipelineIntegration::run(sampleInput()); + bool hasHuman = false; + for (const auto& t : out.tests.tests) { + if (t.kind == SecurityTestKind::SqlInjectionProbe || + t.kind == SecurityTestKind::XssPayload || + t.kind == SecurityTestKind::AuthBypass) { + if (t.routeTo == "human") hasHuman = true; + } + } + CHECK(hasHuman, "expected human-routed penetration tests"); + PASS(); +} + +void test_integration_regression_step491_behavior_still_available() { + TEST(integration_regression_step491_behavior_still_available); + auto out = SecurityPipelineIntegration::run(sampleInput()); + bool hasAccessMatrix = false; + for (const auto& t : out.tests.tests) { + if (t.kind == SecurityTestKind::AccessControlMatrix) hasAccessMatrix = true; + } + CHECK(hasAccessMatrix, "expected access control matrix test"); + PASS(); +} + +int main() { + std::cout << "Step 492: Phase 24b Integration + Sprint Summary Tests\n"; + + test_python_to_rust_translation_preserves_security_annotations(); // 1 + test_generated_sql_and_input_code_use_secure_defaults(); // 2 + test_threat_model_outputs_boundary_diagnostics_when_validation_missing(); // 3 + test_security_test_skeletons_generated_with_meaningful_intent(); // 4 + test_translation_blocking_review_propagates_to_pipeline_notes(); // 5 + test_pipeline_notes_include_execution_trace_summary(); // 6 + test_access_control_and_pen_tests_route_human_in_generated_suite(); // 7 + test_integration_regression_step491_behavior_still_available(); // 8 + + std::cout << "\nResults: " << passed << "/" << (passed + failed) + << " passed\n"; + return failed == 0 ? 0 : 1; +} diff --git a/progress.md b/progress.md index c71c369..b543636 100644 --- a/progress.md +++ b/progress.md @@ -7302,3 +7302,54 @@ coverage is scaffolded alongside code and routed by complexity/risk. - `editor/src/SecurityTestSkeletonGenerator.h` within header-size limit (`140` <= `600`) - `editor/tests/step491_test.cpp` within test-file size guidance (`164` lines) - Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +### Step 492: Phase 24b Integration + Sprint Summary +**Status:** PASS (8/8 tests) + +Integrates Phase 24b security components into one pipeline: +security-preserving translation, secure-by-default generation, threat-model +analysis, and security test skeleton generation. + +**Files added:** +- `editor/src/SecurityPipelineIntegration.h` — composed security pipeline: + - `SecurityPipelineInput`, `SecurityPipelineResult` + - `run(...)` flow: + - `SecurityPreservingTranslation::translate(...)` + - `SecureByDefaultGenerator::generate(...)` for SQL + input handling snippets + - `ThreatModelIntegration::analyze(...)` + - `SecurityTestSkeletonGenerator::generate(...)` + - pipeline notes include execution trace and blocking-review propagation +- `editor/tests/step492_test.cpp` — 8 integration tests covering: + - Python->Rust security annotation preservation + - secure-default SQL/input generation checks + - threat-model diagnostics on missing validation + - security test skeleton quality/routing checks + - blocking-review propagation from translation stage + - phase regression expectations against Step 491 behavior +- `editor/CMakeLists.txt` — `step492_test` target + +**Verification run:** +- `cmake --build editor/build-native --target step492_test step491_test` — PASS +- `./editor/build-native/step492_test` — PASS (8/8) +- `./editor/build-native/step491_test` — PASS (12/12) regression coverage + +**Architecture gate check:** +- `editor/src/SecurityPipelineIntegration.h` within header-size limit (`61` <= `600`) +- `editor/tests/step492_test.cpp` within test-file size guidance (`137` lines) +- Header-only architecture and naming conventions remain aligned with `ARCHITECTURE.md` + +**Phase 24b totals (488-492):** +- **Steps:** 5 +- **Tests:** 56/56 passing +- **Headers added:** 5 + - `SecurityPreservingTranslation.h` + - `SecureByDefaultGenerator.h` + - `ThreatModelIntegration.h` + - `SecurityTestSkeletonGenerator.h` + - `SecurityPipelineIntegration.h` +- **Capabilities delivered:** + - security annotation preservation across transpilation boundaries + - secure-by-default generation for SQL/input/file/network/crypto patterns + - trust boundary + data-flow threat diagnostics (`E1300` range) + - routed security test skeleton generation + - end-to-end security pipeline integration