Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
64 changes: 47 additions & 17 deletions docs/ci.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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

Expand All @@ -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

Expand All @@ -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.
Expand All @@ -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ışı

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.

Expand Down
20 changes: 18 additions & 2 deletions docs/components/dependency-scanner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 4 additions & 3 deletions docs/components/sample-web-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions docs/components/sample-web-app/analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions docs/components/sample-web-app/technical-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -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ı

Expand Down
62 changes: 61 additions & 1 deletion tests/test_ci_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
)
_ACTION_PATTERN = re.compile(
r"uses: "
r"(?P<action>actions/(?:checkout|setup-python))"
r"(?P<action>actions/(?:checkout|setup-python|upload-artifact))"
r"@(?P<sha>[0-9a-f]{40})"
r" # (?P<version>v[0-9]+\.[0-9]+\.[0-9]+)"
)
Expand Down Expand Up @@ -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",
),
}


Expand Down Expand Up @@ -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