Skip to content

cast init generate devsecops.yml but has syntax error #5

@shenxianpeng

Description

@shenxianpeng

I used cast init and select the 2 then generate

[Invalid workflow file: .github/workflows/devsecops.yml#L163](https://github.com/castops/tests/actions/runs/23688702679/workflow)
You have an error in your yaml syntax on line 163

here are the devsecops.yml

# CAST — DevSecOps Pipeline for Node.js
# https://github.com/castops/cast
#
# Includes:
#   1. Secrets Detection  — Gitleaks
#   2. SAST               — Semgrep
#   3. SCA                — npm audit
#   4. Container Security — Trivy  (skipped if no Dockerfile)
#   5. Code Quality       — ESLint
#   6. Security Gate      — conftest policy evaluation on SARIF findings

name: CAST DevSecOps

on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]
  workflow_dispatch:

permissions:
  contents: read
  security-events: write  # required for SARIF upload to GitHub Security tab
  actions: read

jobs:

  # ── 1. Secrets Detection ───────────────────────────────────────────────────
  secrets:
    name: Secrets Detection
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # full history so Gitleaks can scan all commits
      - name: Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  # ── 2. SAST ────────────────────────────────────────────────────────────────
  sast:
    name: SAST
    runs-on: ubuntu-latest
    container:
      image: semgrep/semgrep
    steps:
      - uses: actions/checkout@v4
      - name: Semgrep scan
        run: semgrep ci --sarif --output=semgrep.sarif || true
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
      - name: Upload to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: semgrep.sarif
      - name: Upload SARIF artifact
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: cast-sarif-sast
          path: semgrep.sarif

  # ── 3. SCA — Dependency Audit ──────────────────────────────────────────────
  sca:
    name: SCA
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "lts/*"
          cache: npm
      - name: Install dependencies
        run: npm ci --prefer-offline
      - name: npm audit
        run: npm audit --audit-level=high

  # ── 4. Container Security ──────────────────────────────────────────────────
  container:
    name: Container Security
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check for Dockerfile
        id: check_dockerfile
        run: |
          if [ -f Dockerfile ]; then
            echo "found=true" >> $GITHUB_OUTPUT
          else
            echo "No Dockerfile found — skipping container scan"
            echo "found=false" >> $GITHUB_OUTPUT
          fi
      - name: Build image
        if: steps.check_dockerfile.outputs.found == 'true'
        run: docker build -t cast-scan:${{ github.sha }} .
      - name: Trivy scan
        if: steps.check_dockerfile.outputs.found == 'true'
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: cast-scan:${{ github.sha }}
          format: sarif
          output: trivy.sarif
          severity: CRITICAL,HIGH
          exit-code: "0"  # gate handles blocking, not trivy directly
      - name: Upload to GitHub Security tab
        if: steps.check_dockerfile.outputs.found == 'true'
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy.sarif
      - name: Upload SARIF artifact
        if: steps.check_dockerfile.outputs.found == 'true'
        uses: actions/upload-artifact@v4
        with:
          name: cast-sarif-container
          path: trivy.sarif

  # ── 5. Code Quality ────────────────────────────────────────────────────────
  quality:
    name: Code Quality
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "lts/*"
          cache: npm
      - name: Install dependencies
        run: npm ci --prefer-offline
      - name: ESLint
        run: npx eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0

  # ── 6. Security Gate ───────────────────────────────────────────────────────
  gate:
    name: Security Gate
    runs-on: ubuntu-latest
    needs: [secrets, sast, sca, container, quality]
    if: always()
    steps:
      - uses: actions/checkout@v4
      - name: Download SARIF results
        uses: actions/download-artifact@v4
        with:
          pattern: cast-sarif-*
          path: sarif-results/
          merge-multiple: true
        continue-on-error: true
      - name: Install conftest
        run: |
          curl -fsSL -o conftest.tar.gz \
            https://github.com/open-policy-agent/conftest/releases/download/v0.50.0/conftest_0.50.0_Linux_x86_64.tar.gz
          tar xzf conftest.tar.gz conftest
          chmod +x conftest && sudo mv conftest /usr/local/bin/
      - name: Write default policy
        run: |
          # Use local policy/ directory if present; otherwise write the built-in default.
          # For strict/permissive mode, copy the desired .rego from:
          #   https://github.com/castops/cast/tree/main/policy
          if [ ! -d policy ] || [ -z "$(ls -A policy/*.rego 2>/dev/null)" ]; then
            mkdir -p policy
            cat > policy/active.rego << 'REGO'
package main

import future.keywords.if
import future.keywords.in

deny[msg] if {
    run := input.runs[_]
    result := run.results[_]
    result.level == "error"
    tool := run.tool.driver.name
    msg := sprintf("[CRITICAL] %s — %s (rule: %s)", [tool, result.message.text, result.ruleId])
}
REGO
          fi
      - name: Evaluate policy
        run: |
          GATE_FAILED=0

          # Run conftest on any SARIF files collected
          if compgen -G "sarif-results/*.sarif" > /dev/null 2>&1; then
            conftest test sarif-results/*.sarif --policy policy/ \
              || GATE_FAILED=1
          fi

          # Check job results for non-SARIF tools
          if [[ "${{ needs.secrets.result }}" == "failure" ]]; then
            echo "❌ Secrets Detection failed"
            GATE_FAILED=1
          fi
          if [[ "${{ needs.sca.result }}" == "failure" ]]; then
            echo "❌ SCA (npm audit) failed"
            GATE_FAILED=1
          fi

          if [ "$GATE_FAILED" -eq 1 ]; then
            echo "❌ Security gate blocked merge"
            exit 1
          fi

          echo "✅ All security checks passed — safe to merge"

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions