Skip to content
This repository was archived by the owner on Jul 13, 2026. It is now read-only.
This repository was archived by the owner on Jul 13, 2026. It is now read-only.

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

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"

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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