From ebafb1e5f811fa200888fcaa507f08aadc973854 Mon Sep 17 00:00:00 2001 From: batuthzcode Date: Tue, 18 Aug 2026 15:55:52 +0300 Subject: [PATCH 1/3] ci: upload security report artifacts --- .github/workflows/ci.yml | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f366b32..6edf05c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,35 @@ jobs: reports/sample-app/static-analysis.json python -m pytest tests/test_sample_app_security_demo.py -q + - name: Verify static analysis reports + if: ${{ !cancelled() }} + shell: bash + run: | + reports=( + reports/ci/static-analysis-src.json + reports/ci/static-analysis-tools.json + reports/ci/static-analysis-sample-app.json + ) + + for report in "${reports[@]}"; do + if [ ! -s "$report" ]; then + echo "Required report is missing or empty: $report" + exit 1 + fi + done + + - name: Upload static analysis reports + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: static-analysis-reports-${{ github.run_attempt }} + path: | + reports/ci/static-analysis-src.json + reports/ci/static-analysis-tools.json + reports/ci/static-analysis-sample-app.json + if-no-files-found: error + retention-days: 14 + dependency-scan: name: Dependency scan needs: test @@ -130,3 +159,23 @@ jobs: python -m pytest \ tests/test_ci_dependency_scan.py \ tests/test_dependency_integration.py -q + + - name: Verify dependency report + if: ${{ !cancelled() }} + shell: bash + run: | + report=reports/ci/dependency-scan.json + + if [ ! -s "$report" ]; then + echo "Required report is missing or empty: $report" + exit 1 + fi + + - name: Upload dependency report + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: dependency-scan-report-${{ github.run_attempt }} + path: reports/ci/dependency-scan.json + if-no-files-found: error + retention-days: 14 From c4ce3029afba22827bb9b124d2fc623a5256ebb2 Mon Sep 17 00:00:00 2001 From: batuthzcode Date: Tue, 18 Aug 2026 15:55:53 +0300 Subject: [PATCH 2/3] test(ci): validate security report artifacts --- tests/test_ci_workflow.py | 62 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/test_ci_workflow.py b/tests/test_ci_workflow.py index e0e303d..536acc5 100644 --- a/tests/test_ci_workflow.py +++ b/tests/test_ci_workflow.py @@ -12,7 +12,7 @@ ) _ACTION_PATTERN = re.compile( r"uses: " - r"(?Pactions/(?:checkout|setup-python))" + r"(?Pactions/(?:checkout|setup-python|upload-artifact))" r"@(?P[0-9a-f]{40})" r" # (?Pv[0-9]+\.[0-9]+\.[0-9]+)" ) @@ -86,6 +86,10 @@ def test_official_actions_are_pinned_to_expected_commits() -> None: "5fda3b95a4ea91299a34e894583c3862153e4b97", "v7.0.0", ), + "actions/upload-artifact": ( + "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a", + "v7.0.1", + ), } @@ -242,3 +246,59 @@ def test_dependency_scan_job_validates_offline_report() -> None: assert "reports/sample-app/dependency-scan.json" in workflow assert "tests/test_ci_dependency_scan.py" in workflow assert "tests/test_dependency_integration.py -q" in workflow + + +def test_static_analysis_reports_are_uploaded() -> None: + """All static JSON reports should share one bounded artifact.""" + + workflow = _workflow_text() + + assert "name: Verify static analysis reports" in workflow + assert "name: Upload static analysis reports" in workflow + assert ( + "name: static-analysis-reports-" + "${{ github.run_attempt }}" + in workflow + ) + assert ( + "path: |\n" + " reports/ci/static-analysis-src.json\n" + " reports/ci/static-analysis-tools.json\n" + " reports/ci/static-analysis-sample-app.json\n" + in workflow + ) + + +def test_dependency_report_is_uploaded() -> None: + """The CVE JSON report should have its own bounded artifact.""" + + workflow = _workflow_text() + + assert "name: Verify dependency report" in workflow + assert "name: Upload dependency report" in workflow + assert ( + "name: dependency-scan-report-" + "${{ github.run_attempt }}" + in workflow + ) + assert "path: reports/ci/dependency-scan.json" in workflow + + +def test_report_uploads_fail_closed_with_bounded_retention() -> None: + """Missing reports should fail and artifacts should expire.""" + + workflow = _workflow_text() + upload_action = ( + "actions/upload-artifact@" + "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a " + "# v7.0.1" + ) + + assert workflow.count(upload_action) == 2 + assert workflow.count("if: ${{ !cancelled() }}") == 4 + assert workflow.count("if-no-files-found: error") == 2 + assert workflow.count("retention-days: 14") == 2 + assert workflow.count( + 'echo "Required report is missing or empty: $report"' + ) == 2 + assert "continue-on-error: true" not in workflow From 0dc3b5974d588e4a616cd12037544dd6326dfa8d Mon Sep 17 00:00:00 2001 From: batuthzcode Date: Tue, 18 Aug 2026 15:55:53 +0300 Subject: [PATCH 3/3] docs(ci): document security report retention --- docs/ci.md | 64 ++++++++++++++----- docs/components/dependency-scanner/README.md | 20 +++++- docs/components/sample-web-app/README.md | 7 +- docs/components/sample-web-app/analysis.md | 8 ++- .../sample-web-app/technical-design.md | 5 +- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/docs/ci.md b/docs/ci.md index 6fc6dac..a6b7e5a 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -1,13 +1,13 @@ # GitHub Actions CI -Bu doküman Backlog 5.1, 5.2 ve 5.3 kapsamındaki test, statik analiz ve -bağımlılık tarama pipeline'ının gereksinimlerini, güvenlik sınırlarını ve -çalışma sırasını açıklar. +Bu doküman Backlog 5.1, 5.2, 5.3 ve 5.4 kapsamındaki test, statik analiz, +bağımlılık tarama ve rapor artifact pipeline'ının gereksinimlerini, güvenlik +sınırlarını ve çalışma sırasını açıklar. ## Mevcut Durum -GitHub Actions test, statik analiz ve bağımlılık tarama workflow'u -tamamlanmıştır: +GitHub Actions test, statik analiz, bağımlılık tarama ve güvenlik raporu +saklama workflow'u tamamlanmıştır: ```text .github/workflows/ci.yml @@ -17,8 +17,8 @@ Workflow Pull Request değişikliklerinde ve `main` branch push olaylarında Python 3.11 test paketini çalıştırır. Test gate'i geçtikten sonra proje kaynaklarını ve kontrollü demo uygulamasını ayrı bir static-analysis job'unda tarar. Buna paralel dependency-scan job'u, checked-in OSV fixture ile kritik -güvenlik açığı gate'ini çalıştırır. Sıradaki aşama report artifact upload -job'udur. +güvenlik açığı gate'ini çalıştırır. İki güvenlik job'u ürettikleri doğrulanmış +JSON raporlarını 14 günlük GitHub Actions artifact'ları olarak saklar. ## Trigger Sözleşmesi @@ -43,8 +43,9 @@ Checkout sonrasında credential persistence kapalıdır. Üç job da `ubuntu-latest` runner üzerinde en fazla 10 dakika çalışır. Aynı workflow ve Git ref için yeni bir run başladığında önceki run iptal edilir. -Bu job'lar secret, write permission, deployment environment veya external -service credential kullanmaz. +Bu job'lar secret, repository write permission, deployment environment veya +harici service credential kullanmaz. Artifact upload, GitHub Actions'ın job +çalışma bağlamındaki yerleşik artifact servisini kullanır. ## Action Pinleri @@ -55,6 +56,7 @@ commit SHA değerleri kullanılır: |---|---|---| | `actions/checkout` | `v7.0.1` | `3d3c42e5aac5ba805825da76410c181273ba90b1` | | `actions/setup-python` | `v7.0.0` | `5fda3b95a4ea91299a34e894583c3862153e4b97` | +| `actions/upload-artifact` | `v7.0.1` | `043fb46d1a93c77aae656e7c1c64a875d1fc6a0a` | Yorumdaki release etiketi bakım sırasında SHA provenance değerinin kolayca kontrol edilmesini sağlar. @@ -63,6 +65,7 @@ Resmî release kaynakları: - [actions/checkout v7.0.1](https://github.com/actions/checkout/releases/tag/v7.0.1) - [actions/setup-python v7.0.0](https://github.com/actions/setup-python/releases/tag/v7.0.0) +- [actions/upload-artifact v7.0.1](https://github.com/actions/upload-artifact/releases/tag/v7.0.1) ## Test Job Akışı @@ -103,9 +106,6 @@ modeli `INFO`, `WARNING` ve `ERROR` seviyelerini kullandığından `HIGH` ve karşılaştırılır; ardından kontrollü demo entegrasyon testleri çalıştırılır. Exit code veya baseline değişirse job başarısız olur. -Bu aşamada `reports/ci` yalnızca job workspace'inde tutulur. Artifact upload -Backlog 5.4 kapsamında eklenecektir. - ## Bağımlılık Tarama Job Akışı `dependency-scan` job'u test job'una bağlıdır ve statik analiz job'uyla @@ -140,6 +140,33 @@ düzeyinde karşılaştırılır. Ardından offline CI ve production-layer depen entegrasyon testleri çalıştırılır. Böylece ağ erişilebilirliği pipeline sonucunu etkilemez ve fixture drift'i sessizce kabul edilmez. +## Güvenlik Raporu Artifact Akışı + +Raporlar üretildikleri job'dan doğrudan yüklenir. Böylece ayrı bir aggregation +job'u, job'lar arası geçici indirme veya genişletilmiş token izni gerekmez. + +Her workflow attempt'i aşağıdaki iki artifact'ı oluşturur: + +| Artifact | İçerik | +|---|---| +| `static-analysis-reports-${{ github.run_attempt }}` | `static-analysis-src.json`, `static-analysis-tools.json`, `static-analysis-sample-app.json` | +| `dependency-scan-report-${{ github.run_attempt }}` | `dependency-scan.json` | + +Artifact adından `github.run_attempt` kullanılması, aynı workflow run'ı yeniden +çalıştırıldığında immutable artifact adlarının çakışmasını önler. + +Upload öncesinde her gerekli dosya Bash `-s` kontrolüyle hem varlık hem boş +olmama açısından doğrulanır. Doğrulama ve upload adımları `!cancelled()` +koşuluyla normal başarıda ve önceki adım başarısız olduğunda çalışır; iptal +edilmiş run için eksik veya yarım artifact yayınlanmaz. Gerekli dosya eksik ya +da boşsa job başarısız kalır. `if-no-files-found: error` aynı davranışı action +seviyesinde ikinci kez korur ve `continue-on-error` kullanılmaz. + +Her iki artifact 14 gün saklanır. Yalnızca makine tarafından okunabilir JSON +raporları yüklenir; source checkout, dependency cache, log veya credential +artifact kapsamına alınmaz. Upload action'ı diğer resmî action'lar gibi tam +commit SHA değerine sabitlenmiştir. + ## Yerel Eşdeğer CI test adımını yerelde doğrulamak için: @@ -200,7 +227,7 @@ python -m pytest tests/test_python_compatibility.py -q - Salt-okunur repository permission - Checkout credential persistence yasağı - Concurrency cancellation -- İki action için tam 40 karakterli SHA ve release etiketi +- Üç action için tam 40 karakterli SHA ve release etiketi - Python 3.11 ve pip cache yapılandırması - Pip upgrade, dev install ve pytest komut sırası - Ubuntu runner ve 10 dakikalık timeout @@ -210,6 +237,9 @@ python -m pytest tests/test_python_compatibility.py -q - Test job'una bağlı offline dependency-scan job'u - Açık requirements, fixture, output ve `critical` eşik değerleri - Dependency baseline ve entegrasyon testi doğrulaması +- İki güvenlik artifact'ının ayrı, attempt-safe adları ve kesin dosya kapsamı +- Eksik/boş rapor için fail-closed kontrol ve `if-no-files-found: error` +- 14 günlük sınırlı saklama süresi ve iptal edilen run upload yasağı `tests/test_python_compatibility.py`, `src`, `sample_app`, `tools` ve `tests` altındaki bütün Python dosyalarını desteklenen en düşük sürüm olan Python @@ -219,18 +249,18 @@ geçen Python 3.12+ söz dizimi değişiklikleri CI'a ulaşmadan tespit edilir. Doğrulanan mevcut sonuç: ```text -CI workflow contract tests: 13 passed +CI workflow contract tests: 16 passed Offline dependency CI tests: 6 passed Python 3.11 compatibility tests: 1 passed -Complete test suite: 997 passed +Complete test suite: 1000 passed Workflow YAML parse check: passed ``` ## Sonraki Güvenlik Job'ları -Backlog 5.1, 5.2 ve 5.3 tamamlanmıştır. Sonraki aşama: +Backlog 5.1, 5.2, 5.3 ve 5.4 tamamlanmıştır. Sonraki aşama: -1. Static ve dependency JSON raporlarını workflow artifact olarak yükleme +1. Backlog 5.5 kapsamında eksik test ve self-analysis kapsamını tamamlama Bu ayrım her güvenlik gate'inin davranışını bağımsız olarak incelemeyi sağlar. diff --git a/docs/components/dependency-scanner/README.md b/docs/components/dependency-scanner/README.md index 4c97d9c..57ed71c 100644 --- a/docs/components/dependency-scanner/README.md +++ b/docs/components/dependency-scanner/README.md @@ -1768,11 +1768,27 @@ Güncel doğrulama: ```text Offline dependency CI tests: 6 passed -CI workflow contract tests: 13 passed -Complete test suite: 997 passed +CI workflow contract tests: 16 passed +Complete test suite: 1000 passed Live HTTP requests: disabled ``` +## CI Report Artifact + +Backlog 5.4 kapsamında doğrulanmış dependency JSON raporu aynı +`dependency-scan` job'undan aşağıdaki adla yüklenir: + +```text +dependency-scan-report-${{ github.run_attempt }} +``` + +Artifact yalnızca `reports/ci/dependency-scan.json` dosyasını içerir ve 14 gün +saklanır. Upload öncesindeki non-empty kontrol ile action'ın +`if-no-files-found: error` politikası eksik raporu pipeline hatasına çevirir. +Upload adımı önceki bir scan/validation hatasından sonra tanı raporunu +korumak için çalışır; iptal edilen run'larda çalışmaz. Action tam commit SHA +değerine sabitlenmiştir ve repository write izni gerektirmez. + ## Navigation - [Tüm bileşenlere dön](../README.md) diff --git a/docs/components/sample-web-app/README.md b/docs/components/sample-web-app/README.md index 5a1ebbf..20174d2 100644 --- a/docs/components/sample-web-app/README.md +++ b/docs/components/sample-web-app/README.md @@ -61,8 +61,9 @@ Mevcut özellikler: * Portable static-analysis ve dependency-scan JSON baseline'ları * Offline report generator ve drift check * Pull Request ve `main` push için test, static ve dependency CI job'ları +* 14 günlük static-analysis ve dependency-scan CI report artifact'ları -Sıradaki aşama security report artifact upload job'udur. +Sıradaki aşama eksik test ve self-analysis kapsamının tamamlanmasıdır. ## Kurulum @@ -547,11 +548,11 @@ New update/delete test cases: 54 passed New frontend test cases: 18 passed New security demo test cases: 4 passed New integration report test cases: 6 passed -New CI workflow test cases: 13 passed +New CI workflow test cases: 16 passed New offline dependency CI test cases: 6 passed New Python 3.11 compatibility test cases: 1 passed Sample app targeted suite: 149 passed -Complete test suite: 997 passed +Complete test suite: 1000 passed Compile check: passed Sample app analysis: 5 expected findings Analyzer source self-analysis: no findings diff --git a/docs/components/sample-web-app/analysis.md b/docs/components/sample-web-app/analysis.md index 017d01b..bb44dc2 100644 --- a/docs/components/sample-web-app/analysis.md +++ b/docs/components/sample-web-app/analysis.md @@ -108,9 +108,11 @@ Temel Flask uygulaması, Task modeli, in-memory store, JSON CRUD endpoint'leri, minimal Jinja/CSS frontend, kontrollü güvenlik fixture'ları ve uçtan uca entegrasyon raporları tamamlanmıştır. -Temel GitHub Actions pytest workflow'u da tamamlanmıştır. Sıradaki geliştirme -adımı analyzer, dependency scanner ve report artifact job'larının pipeline'a -eklenmesidir. +GitHub Actions test, analyzer ve offline dependency scanner job'ları da +tamamlanmıştır. Doğrulanmış static ve dependency JSON raporları 14 günlük, +eksik dosyada fail-closed davranan workflow artifact'ları olarak saklanır. +Sıradaki geliştirme adımı eksik test ve self-analysis kapsamının +tamamlanmasıdır. ## Flask Uygulama İskeleti Gereksinimleri diff --git a/docs/components/sample-web-app/technical-design.md b/docs/components/sample-web-app/technical-design.md index 7dabc24..3d19096 100644 --- a/docs/components/sample-web-app/technical-design.md +++ b/docs/components/sample-web-app/technical-design.md @@ -202,11 +202,12 @@ Tamamlanan foundation çalışmaları: * Tek komutlu report generator ve drift check'in eklenmesi * Uçtan uca demo sırasının belgelenmesi * GitHub Actions pytest foundation workflow'unun eklenmesi +* Analyzer ve offline dependency scanner CI gate'lerinin eklenmesi +* JSON security report artifact upload adımlarının eklenmesi Sıradaki geliştirmeler: -* Analyzer ve dependency scanner CI adımlarının eklenmesi -* JSON security report artifact upload adımının eklenmesi +* Eksik test ve self-analysis kapsamının tamamlanması ## Flask Foundation Teknik Tasarımı