From a753aedd0db6d66a5aa2a78739cac72cd65f1f32 Mon Sep 17 00:00:00 2001 From: Muhamad Sazwan Bin Ismail Date: Wed, 11 Mar 2026 13:11:48 +0800 Subject: [PATCH] Create moda-ci.yaml for Docker security scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add MODA CI pipeline workflow with Docker security scan. ```yaml # .github/workflows/moda-ci.yaml name: MODA CI - Docker Security Scan on: push: branches: [ main, develop ] pull_request: branches: [ main ] schedule: - cron: '0 2 * * 0' # weekly scan on Sunday at 2am workflow_dispatch: jobs: docker-security-scan: name: Call reusable Docker security workflow # Reference the reusable workflow from internal repository uses: github/internal-actions/.github/workflows/docker_security.yml@main with: # Image name – adjust if you need a specific tag format image-name: ${{ github.repository }}:${{ github.sha }} # Path to Dockerfile (relative to repository root) dockerfile-path: ./Dockerfile # Build context (usually the directory containing the Dockerfile) build-context: . # Optional: enable fail on critical vulnerabilities fail-on-critical: true # Optional: specify platform if multi‑arch build is needed # platform: linux/amd64,linux/arm64 secrets: # Docker registry credentials (if your image is pushed to a private registry) registry-username: ${{ secrets.DOCKER_USERNAME }} registry-password: ${{ secrets.DOCKER_PASSWORD }} # Snyk token for vulnerability scanning (if used by the reusable workflow) snyk-token: ${{ secrets.SNYK_TOKEN }} # Slack webhook for notifications (optional) slack-webhook: ${{ secrets.SLACK_WEBHOOK }} ``` **Penjelasan:** - **Trigger**: Workflow ini berjalan pada push ke `main`/`develop`, pull request ke `main`, jadual mingguan, dan boleh dicetus manual. - **Reusable workflow**: Memanggil `docker_security.yml` dari repositori `github/internal-actions` pada branch `main`. Pastikan workflow tersebut wujud dan mempunyai akses yang sesuai. - **Input**: - `image-name`: Gabungan nama repositori dan SHA commit, sesuai untuk penandaan unik. - `dockerfile-path` dan `build-context`: Laluan standard untuk membina imej. - `fail-on-critical`: Jika true, job akan gagal apabila terdapat kelemahan kritikal. - (Ulasan) `platform`: Jika perlu bina untuk pelbagai seni bina, nyahkomen dan laraskan. - **Secrets**: Hantar rahsia yang diperlukan oleh workflow dalaman. Gantikan dengan nama rahsia sebenar yang telah ditetapkan di repositori anda. **Langkah seterusnya:** 1. Simpan fail ini sebagai `.github/workflows/moda-ci.yaml` dalam repositori anda. 2. Tambah sebarang rahsia yang diperlukan (DOCKER_USERNAME, DOCKER_PASSWORD, SNYK_TOKEN, SLACK_WEBHOOK) di **Settings → Secrets and variables → Actions**. 3. Sesuaikan nilai input seperti `fail-on-critical` atau tambah `platform` jika perlu. 4. Uji dengan mencetuskan workflow (misalnya dengan push ke branch). ```yaml # .github/workflows/moda-ci.yaml name: MODA CI – Advanced Docker Security Scan on: push: branches: [ main, develop, release/** ] pull_request: branches: [ main ] schedule: - cron: '0 2 * * 0' # weekly scan every Sunday at 2am workflow_dispatch: inputs: fail-on-critical: description: 'Fail build on critical vulnerabilities?' required: true default: true type: boolean extra-tags: description: 'Additional image tags (comma separated)' required: false default: '' env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: # Matrix job for multiple Dockerfiles or build contexts security-scan: name: Security Scan (${{ matrix.context }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - dockerfile: ./Dockerfile context: . image-suffix: '' - dockerfile: ./api/Dockerfile context: ./api image-suffix: -api # add more as needed steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # Build image for scanning (do not push yet) - name: Build Docker image uses: docker/build-push-action@v5 with: context: ${{ matrix.context }} file: ${{ matrix.dockerfile }} tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan${{ matrix.image-suffix }}-${{ github.sha }} load: true cache-from: type=gha cache-to: type=gha,mode=max # 1. Trivy vulnerability scan - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan${{ matrix.image-suffix }}-${{ github.sha }} format: 'sarif' output: 'trivy-results${{ matrix.image-suffix }}.sarif' severity: 'CRITICAL,HIGH' exit-code: '1' # fail if vulnerabilities found continue-on-error: ${{ !github.event.inputs.fail-on-critical && github.event.inputs.fail-on-critical != 'true' }} - name: Upload Trivy results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results${{ matrix.image-suffix }}.sarif' # 2. Snyk container scan (requires SNYK_TOKEN) - name: Snyk Container scan uses: snyk/actions/docker@master continue-on-error: ${{ !github.event.inputs.fail-on-critical && github.event.inputs.fail-on-critical != 'true' }} env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan${{ matrix.image-suffix }}-${{ github.sha }} args: --file=${{ matrix.dockerfile }} --severity-threshold=high # 3. Grype scan (optional) - name: Grype scan uses: anchore/scan-action@v3 with: image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:scan${{ matrix.image-suffix }}-${{ github.sha }} fail-build: ${{ github.event.inputs.fail-on-critical == 'true' }} severity-cutoff: high # Call internal reusable workflow (if you still want to use it) internal-security-scan: name: Call internal reusable workflow if: false # disable if you prefer the matrix above; remove or set condition as needed uses: github/internal-actions/.github/workflows/docker_security.yml@main with: image-name: ${{ github.repository }}:${{ github.sha }} dockerfile-path: ./Dockerfile build-context: . fail-on-critical: ${{ github.event.inputs.fail-on-critical || true }} secrets: registry-username: ${{ secrets.DOCKER_USERNAME }} registry-password: ${{ secrets.DOCKER_PASSWORD }} snyk-token: ${{ secrets.SNYK_TOKEN }} slack-webhook: ${{ secrets.SLACK_WEBHOOK }} ``` **Ciri-ciri utama:** - **Matrix strategy** – mengimbas berbilang Dockerfile (contoh: utama dan API). - **Imbasan menyeluruh** – Trivy, Snyk, Grype untuk liputan maksimum. - **Hasil SARIF** dimuat naik ke tab Security GitHub. - **Kawalan kegagalan** melalui input `fail-on-critical` (boleh ditetapkan manual). - **Masih menyertakan** panggilan ke reusable workflow dalaman (dilumpuhkan sementara dengan `if: false` – aktifkan jika perlu). **Sesuaikan mengikut keperluan:** - Tambah atau alih keluar alat imbasan. - Laraskan `severity` dan `exit-code` mengikut polisi keselamatan anda. - Gantikan `github/internal-actions/.github/workflows/docker_security.yml@main` dengan workflow sebenar anda. **Secrets yang perlu ditetapkan** (di Settings → Secrets and variables → Actions): - `DOCKER_USERNAME`, `DOCKER_PASSWORD` – jika registry memerlukan log masuk. - `SNYK_TOKEN` – untuk imbasan Snyk. - `SLACK_WEBHOOK` – untuk notifikasi (pilihan). Workflow ini akan memberikan anda kawalan penuh ke atas keselamatan imej Docker anda. --- github/workflows/Workflow-moda-ci.yaml | 257 +++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 github/workflows/Workflow-moda-ci.yaml diff --git a/github/workflows/Workflow-moda-ci.yaml b/github/workflows/Workflow-moda-ci.yaml new file mode 100644 index 000000000000..333fec45bc4f --- /dev/null +++ b/github/workflows/Workflow-moda-ci.yaml @@ -0,0 +1,257 @@ +Berikut adalah contoh fail workflow `moda-ci.yaml` yang memanggil reusable workflow `docker_security.yml` dari repositori dalaman `github/internal-actions`. Anda perlu menyesuaikan nilai input dan memastikan sebarang rahsia (secrets) yang diperlukan telah ditetapkan dalam repositori. + +```yaml +# .github/workflows/moda-ci.yaml +name: MODA CI Pipeline + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + workflow_dispatch: # allow manual trigger + +jobs: + # Panggil reusable workflow untuk keselamatan Docker + security-scan: + name: Docker Security Scan + uses: github/internal-actions/.github/workflows/docker_security.yml@main + with: + # Input yang diperlukan oleh workflow docker_security.yml + # Gantikan dengan nilai yang sesuai untuk projek anda + image-name: ${{ github.repository }}:${{ github.sha }} + dockerfile-path: ./Dockerfile + build-context: . + # Tambah input lain seperti yang dinyatakan dalam workflow tersebut + secrets: + # Sekiranya workflow memerlukan token pendaftaran Docker atau rahsia lain, + # hantarkan di sini. Gantikan dengan nama rahsia yang sesuai. + registry-password: ${{ secrets.REGISTRY_PASSWORD }} + # GITHUB_TOKEN dihantar secara automatik, jadi tidak perlu dinyatakan +``` + +**Penjelasan:** + +- **`uses`**: Merujuk kepada workflow di repositori `github/internal-actions`, fail `.github/workflows/docker_security.yml` pada branch `main`. +- **`with`**: Menghantar input ke workflow yang dipanggil. Gantikan placeholder (`image-name`, `dockerfile-path`, dll.) dengan nilai sebenar yang diperlukan oleh workflow tersebut. Lihat dokumentasi workflow dalaman untuk senarai input penuh. +- **`secrets`**: Menghantar rahsia yang diperlukan. `registry-password` hanyalah contoh; gantikan dengan nama rahsia yang betul. Pastikan rahsia tersebut telah ditetapkan di repositori anda (Settings → Secrets and variables → Actions). + +**Langkah seterusnya:** + +1. **Semak dokumentasi** workflow `docker_security.yml` untuk mengetahui input dan rahsia yang diperlukan. +2. **Tetapkan sebarang rahsia** di repositori anda. +3. **Sesuaikan nama branch** dalam `on.push.branches` mengikut keperluan anda. + +Workflow ini akan dijalankan secara automatik setiap kali anda menolak kod ke `main` atau `develop`, atau membuat pull request ke `main`. Anda juga boleh menjalankannya secara manual melalui tab Actions. +Berikut adalah beberapa contoh tambahan workflow yang memanggil reusable workflow `docker_security.yml` dari repositori dalaman `github/internal-actions`. Setiap contoh menunjukkan situasi berbeza dan cara mengendalikan input, rahsia, serta kawalan aliran. + +--- + +## 📁 **Contoh 1: Workflow dengan Matrix Strategy (Pelbagai Platform)** + +Jika projek anda perlu membina imej Docker untuk pelbagai seni bina (AMD64, ARM64), anda boleh menggunakan matrix untuk memanggil reusable workflow secara berulang. + +```yaml +# .github/workflows/moda-ci-matrix.yaml +name: MODA CI with Matrix + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + # Panggil reusable workflow untuk setiap platform + security-scan: + name: Docker Security Scan (${{ matrix.platform }}) + uses: github/internal-actions/.github/workflows/docker_security.yml@main + strategy: + matrix: + platform: [linux/amd64, linux/arm64] + with: + image-name: ${{ github.repository }}:${{ github.sha }}-${{ matrix.platform }} + dockerfile-path: ./Dockerfile + build-context: . + platform: ${{ matrix.platform }} # input tambahan untuk workflow + secrets: + registry-password: ${{ secrets.REGISTRY_PASSWORD }} +``` + +--- + +## 🔐 **Contoh 2: Menghantar Banyak Rahsia dan Menggunakan Condition** + +Kadangkala reusable workflow memerlukan pelbagai rahsia (misalnya untuk imbasan Snyk, Docker Hub, dsb.). Anda juga boleh mengawal bila workflow dipanggil menggunakan `if`. + +```yaml +# .github/workflows/moda-ci-advanced.yaml +name: MODA CI Advanced + +on: + pull_request: + branches: [ main ] + push: + tags: [ 'v*' ] + +jobs: + call-security: + name: Run Docker Security Checks + # Hanya panggil jika perubahan melibatkan Dockerfile atau fail berkaitan + if: contains(github.event.head_commit.modified, 'Dockerfile') || github.event_name == 'pull_request' + uses: github/internal-actions/.github/workflows/docker_security.yml@main + with: + image-name: ${{ github.repository }}:${{ github.sha }} + dockerfile-path: ./Dockerfile + build-context: . + fail-on-critical: true # contoh input boolean + secrets: + registry-username: ${{ secrets.DOCKER_USERNAME }} + registry-password: ${{ secrets.DOCKER_PASSWORD }} + snyk-token: ${{ secrets.SNYK_TOKEN }} + slack-webhook: ${{ secrets.SLACK_WEBHOOK }} +``` + +--- + +## 🧪 **Contoh 3: Menguji dan Debug dengan Input Pilihan** + +Jika reusable workflow menyokong mod debug, anda boleh menambah input khas untuk debugging. + +```yaml +# .github/workflows/moda-ci-debug.yaml +name: MODA CI Debug + +on: + workflow_dispatch: + inputs: + debug: + description: 'Enable debug mode' + required: false + default: 'false' + type: boolean + +jobs: + debug-scan: + name: Debug Security Scan + uses: github/internal-actions/.github/workflows/docker_security.yml@main + with: + image-name: ${{ github.repository }}:${{ github.sha }} + dockerfile-path: ./Dockerfile + build-context: . + debug: ${{ github.event.inputs.debug }} + # input debug mungkin digunakan dalam workflow untuk menghidupkan logging verbose + secrets: + registry-password: ${{ secrets.REGISTRY_PASSWORD }} +``` + +--- + +## 🔄 **Contoh 4: Memanggil Workflow daripada Branch Berbeza** + +Jika anda sedang membangunkan perubahan pada workflow dalaman, anda boleh memanggilnya dari branch lain (bukan `main`) untuk ujian. + +```yaml +# .github/workflows/moda-ci-test-branch.yaml +name: MODA CI (Test Branch) + +on: + push: + branches: [ feature/new-security-checks ] + +jobs: + test-workflow: + name: Test Workflow from dev branch + # Gantikan @main dengan @nama-branch + uses: github/internal-actions/.github/workflows/docker_security.yml@feature/add-trivy + with: + image-name: ${{ github.repository }}:test + dockerfile-path: ./Dockerfile + build-context: . + secrets: + registry-password: ${{ secrets.REGISTRY_PASSWORD }} +``` + +--- + +## ⚠️ **Contoh 5: Mengendalikan Kegagalan (Continue on Error)** + +Anda boleh membenarkan workflow terus walaupun langkah tertentu gagal, misalnya jika imbasan keselamatan tidak kritikal. + +```yaml +# .github/workflows/moda-ci-continue.yaml +name: MODA CI (Continue on Error) + +on: + push: + branches: [ main ] + +jobs: + call-security: + uses: github/internal-actions/.github/workflows/docker_security.yml@main + with: + image-name: ${{ github.repository }}:${{ github.sha }} + dockerfile-path: ./Dockerfile + build-context: . + secrets: + registry-password: ${{ secrets.REGISTRY_PASSWORD }} + # Jika workflow dalaman gagal, job lain masih boleh dijalankan + continue-on-error: true + + deploy: + needs: call-security + runs-on: ubuntu-latest + steps: + - name: Deploy application + run: echo "Deploying..." +``` + +--- + +## 🧩 **Senarai Semak Input dan Rahsia** + +Sebelum menggunakan reusable workflow, pastikan anda mengetahui input dan rahsia yang diperlukan. Biasanya dokumentasi workflow akan menyenaraikannya. Contoh input yang mungkin: + +| Input | Jenis | Penerangan | +|-------|-------|------------| +| `image-name` | string | Nama penuh imej Docker (termasuk tag) | +| `dockerfile-path` | string | Laluan ke Dockerfile (contoh: `./Dockerfile`) | +| `build-context` | string | Konteks pembinaan (contoh: `.`) | +| `platform` | string | Platform sasaran (contoh: `linux/amd64`) | +| `fail-on-critical` | boolean | Gagalkan job jika terdapat isu kritikal | +| `debug` | boolean | Hidupkan output verbose | + +Rahsia biasa: + +| Rahsia | Penerangan | +|--------|------------| +| `registry-username` | Nama pengguna untuk Docker registry | +| `registry-password` | Kata laluan/token untuk registry | +| `snyk-token` | Token API Snyk untuk imbasan | +| `slack-webhook` | Webhook Slack untuk notifikasi | + +--- + +## 🔍 **Menguji Workflow Tempatan** + +Anda boleh menggunakan alat seperti [`act`](https://github.com/nektos/act) untuk menjalankan GitHub Actions secara tempatan. Ini membantu menguji sebelum push. + +```bash +# Pasang act (macOS) +brew install act + +# Jalankan workflow secara tempatan +act push -j call-security +``` + +Pastikan anda menyediakan fail `.secrets` untuk rahsia tempatan. + +--- + +## 📌 **Kesimpulan** + +Dengan menggunakan reusable workflow, anda dapat: +- Mengurangkan penduaan kod. +- Memastikan konsistensi merentas repositori. +- Memudahkan pengurusan kemas kini keselamatan. + +Sesuaikan contoh di atas dengan keperluan sebenar projek anda. Jika workflow dalaman `docker_security.yml` tidak mempunyai dokumentasi yang jelas, hubungi pemilik repositori untuk mendapatkan senarai input dan rahsia yang tepat.