diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8d5691f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ +## Summary + + +## Type + +- [ ] Feature +- [ ] Bug fix +- [ ] Documentation +- [ ] Refactor +- [ ] CI / Pipeline + +## AI Disclosure + +- [ ] This PR contains AI-generated code +- AI Tool: + +## Changes + + +## Testing + + +## Checklist + +- [ ] Branch follows ODS naming convention +- [ ] PR description follows ODS spec +- [ ] No breaking changes diff --git a/.github/workflows/devsecops.yml b/.github/workflows/devsecops.yml index c96db0e..91388ca 100644 --- a/.github/workflows/devsecops.yml +++ b/.github/workflows/devsecops.yml @@ -8,7 +8,8 @@ # 4. Container Security — Trivy (skipped if no Dockerfile) # 5. Code Quality — Ruff # 6. Template Lint — yamllint on templates/**/*.yml -# 7. Security Gate — blocks merge on critical findings +# 7. ODS Validate — open-delivery-spec/validate-action +# 8. Security Gate — blocks merge on critical findings name: CAST DevSecOps @@ -143,11 +144,24 @@ jobs: # Only lint pure workflow YAML files in .github/workflows/. run: yamllint -d relaxed .github/workflows/*.yml - # ── 7. Security Gate ─────────────────────────────────────────────────────── + # ── 7. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 8. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, quality] + needs: [secrets, sast, sca, quality, ods] if: always() steps: - name: Evaluate results @@ -156,10 +170,12 @@ jobs: echo "sast : ${{ needs.sast.result }}" echo "sca : ${{ needs.sca.result }}" echo "quality : ${{ needs.quality.result }}" + echo "ods : ${{ needs.ods.result }}" if [[ "${{ needs.secrets.result }}" == "failure" || "${{ needs.sast.result }}" == "failure" || - "${{ needs.sca.result }}" == "failure" ]]; then + "${{ needs.sca.result }}" == "failure" || + "${{ needs.ods.result }}" == "failure" ]]; then echo "❌ Security gate failed — merge blocked" exit 1 fi diff --git a/CHANGELOG.md b/CHANGELOG.md index e07fec6..15de1d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +- **ODS Validate** — integrated `open-delivery-spec/validate-action@v1` into all + DevSecOps workflows (`.github/workflows/devsecops.yml` and all templates). + Validates branch naming, commit messages, and PR descriptions against + [Open Delivery Spec](https://github.com/open-delivery-spec/spec) standards. + Non-conformant submissions block the security gate. + ## [0.1.1] — 2026-03-24 ### Changed diff --git a/src/cast_cli/templates/go/devsecops.yml b/src/cast_cli/templates/go/devsecops.yml index fa4f1fb..f6ddb30 100644 --- a/src/cast_cli/templates/go/devsecops.yml +++ b/src/cast_cli/templates/go/devsecops.yml @@ -7,7 +7,8 @@ # 3. SCA — govulncheck # 4. Container Security — Trivy (skipped if no Dockerfile) # 5. Code Quality — staticcheck -# 6. Security Gate — conftest policy evaluation on SARIF findings +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — conftest policy evaluation on SARIF findings name: CAST DevSecOps @@ -131,11 +132,24 @@ jobs: go install honnef.co/go/tools/cmd/staticcheck@latest staticcheck ./... - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -193,6 +207,10 @@ REGO echo "❌ SCA (govulncheck) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge" diff --git a/src/cast_cli/templates/nodejs/devsecops.yml b/src/cast_cli/templates/nodejs/devsecops.yml index bdbd4e2..da33183 100644 --- a/src/cast_cli/templates/nodejs/devsecops.yml +++ b/src/cast_cli/templates/nodejs/devsecops.yml @@ -7,7 +7,8 @@ # 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 +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — conftest policy evaluation on SARIF findings name: CAST DevSecOps @@ -131,11 +132,24 @@ jobs: - name: ESLint run: npx eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0 - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -193,6 +207,10 @@ REGO echo "❌ SCA (npm audit) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge" diff --git a/src/cast_cli/templates/python/devsecops.yml b/src/cast_cli/templates/python/devsecops.yml index f38912f..54cbd3c 100644 --- a/src/cast_cli/templates/python/devsecops.yml +++ b/src/cast_cli/templates/python/devsecops.yml @@ -7,7 +7,8 @@ # 3. SCA — pip-audit # 4. Container Security — Trivy (skipped if no Dockerfile) # 5. Code Quality — Ruff -# 6. Security Gate — blocks merge on critical findings +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — blocks merge on critical findings name: CAST DevSecOps @@ -125,11 +126,24 @@ jobs: - uses: actions/checkout@v4 - uses: astral-sh/ruff-action@v1 - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -187,6 +201,10 @@ REGO echo "❌ SCA (pip-audit) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge" diff --git a/templates/go/devsecops.yml b/templates/go/devsecops.yml index 523a6da..c463413 100644 --- a/templates/go/devsecops.yml +++ b/templates/go/devsecops.yml @@ -7,7 +7,8 @@ # 3. SCA — govulncheck # 4. Container Security — Trivy (skipped if no Dockerfile) # 5. Code Quality — staticcheck -# 6. Security Gate — conftest policy evaluation on SARIF findings +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — conftest policy evaluation on SARIF findings name: CAST DevSecOps @@ -131,11 +132,24 @@ jobs: go install honnef.co/go/tools/cmd/staticcheck@latest staticcheck ./... - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -193,6 +207,10 @@ REGO echo "❌ SCA (govulncheck) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge" diff --git a/templates/nodejs/devsecops.yml b/templates/nodejs/devsecops.yml index 0f3f5af..9964dfc 100644 --- a/templates/nodejs/devsecops.yml +++ b/templates/nodejs/devsecops.yml @@ -7,7 +7,8 @@ # 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 +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — conftest policy evaluation on SARIF findings name: CAST DevSecOps @@ -131,11 +132,24 @@ jobs: - name: ESLint run: npx eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0 - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -193,6 +207,10 @@ REGO echo "❌ SCA (npm audit) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge" diff --git a/templates/python/devsecops.yml b/templates/python/devsecops.yml index 28d8c27..21876dc 100644 --- a/templates/python/devsecops.yml +++ b/templates/python/devsecops.yml @@ -7,7 +7,8 @@ # 3. SCA — pip-audit # 4. Container Security — Trivy (skipped if no Dockerfile) # 5. Code Quality — Ruff -# 6. Security Gate — blocks merge on critical findings +# 6. ODS Validate — open-delivery-spec/validate-action +# 7. Security Gate — blocks merge on critical findings name: CAST DevSecOps @@ -125,11 +126,24 @@ jobs: - uses: actions/checkout@v4 - uses: astral-sh/ruff-action@v1 - # ── 6. Security Gate ─────────────────────────────────────────────────────── + # ── 6. ODS Validate ──────────────────────────────────────────────────────── + ods: + name: ODS Validate + runs-on: ubuntu-latest + steps: + - uses: open-delivery-spec/validate-action@v1 + with: + check: all + branch_name: ${{ github.head_ref }} + commit_message: ${{ github.event.head_commit.message }} + pr_body: ${{ github.event.pull_request.body }} + strict: "true" + + # ── 7. Security Gate ─────────────────────────────────────────────────────── gate: name: Security Gate runs-on: ubuntu-latest - needs: [secrets, sast, sca, container, quality] + needs: [secrets, sast, sca, container, quality, ods] if: always() steps: - uses: actions/checkout@v4 @@ -187,6 +201,10 @@ REGO echo "❌ SCA (pip-audit) failed" GATE_FAILED=1 fi + if [[ "${{ needs.ods.result }}" == "failure" ]]; then + echo "❌ ODS Validate failed" + GATE_FAILED=1 + fi if [ "$GATE_FAILED" -eq 1 ]; then echo "❌ Security gate blocked merge"