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
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Summary
<!-- Briefly describe the purpose of this PR -->

## Type
<!-- Check the type(s) that apply -->
- [ ] Feature
- [ ] Bug fix
- [ ] Documentation
- [ ] Refactor
- [ ] CI / Pipeline

## AI Disclosure
<!-- Required by ODS spec -->
- [ ] This PR contains AI-generated code
- AI Tool: <!-- if applicable -->

## Changes
<!-- List key changes -->

## Testing
<!-- How was this tested? -->

## Checklist
<!-- Required by ODS spec -->
- [ ] Branch follows ODS naming convention
- [ ] PR description follows ODS spec
- [ ] No breaking changes
24 changes: 20 additions & 4 deletions .github/workflows/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -36,7 +37,7 @@
fetch-depth: 0 # full history so Gitleaks can scan all commits
- name: Install Gitleaks
run: |
curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.27.2/gitleaks_8.27.2_linux_x64.tar.gz \

Check warning on line 40 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

40:81 [line-length] line too long (118 > 80 characters)
-o /tmp/gitleaks.tar.gz
tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
sudo mv /tmp/gitleaks /usr/local/bin/gitleaks
Expand All @@ -60,11 +61,11 @@
- name: Ensure SARIF exists
if: always()
run: |
[ -f semgrep.sarif ] || echo '{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json","runs":[]}' > semgrep.sarif

Check warning on line 64 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

64:81 [line-length] line too long (193 > 80 characters)
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
continue-on-error: true # requires GitHub Advanced Security; skip gracefully if not enabled

Check warning on line 68 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

68:81 [line-length] line too long (100 > 80 characters)
with:
sarif_file: semgrep.sarif

Expand All @@ -83,7 +84,7 @@
pip install pip-audit
pip install -e ".[dev]"
# CVE-2026-4539: ReDoS in pygments AdlLexer — no fix released yet
# (https://github.com/advisories/GHSA-5239-wwwm-4pmq); re-enable once patched

Check warning on line 87 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

87:81 [line-length] line too long (87 > 80 characters)
pip-audit --ignore-vuln CVE-2026-4539

# ── 4. Container Security ──────────────────────────────────────────────────
Expand Down Expand Up @@ -116,7 +117,7 @@
- name: Upload to GitHub Security tab
if: steps.check_dockerfile.outputs.found == 'true'
uses: github/codeql-action/upload-sarif@v3
continue-on-error: true # requires GitHub Advanced Security; skip gracefully if not enabled

Check warning on line 120 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

120:81 [line-length] line too long (100 > 80 characters)
with:
sarif_file: trivy.sarif

Expand All @@ -137,17 +138,30 @@
- name: Install yamllint
run: pip install yamllint
- name: Lint workflow files
# Templates embed shell heredocs whose content is intentionally at column 1

Check warning on line 141 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

141:81 [line-length] line too long (83 > 80 characters)
# (required by bash heredoc syntax). GitHub Actions handles this correctly,

Check warning on line 142 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

142:81 [line-length] line too long (83 > 80 characters)
# but yamllint's YAML parser reports false-positive syntax errors for such files.

Check warning on line 143 in .github/workflows/devsecops.yml

View workflow job for this annotation

GitHub Actions / Template Lint

143:81 [line-length] line too long (89 > 80 characters)
# 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
Expand All @@ -156,10 +170,12 @@
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
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 21 additions & 3 deletions src/cast_cli/templates/go/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
24 changes: 21 additions & 3 deletions src/cast_cli/templates/nodejs/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
24 changes: 21 additions & 3 deletions src/cast_cli/templates/python/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
24 changes: 21 additions & 3 deletions templates/go/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
24 changes: 21 additions & 3 deletions templates/nodejs/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
24 changes: 21 additions & 3 deletions templates/python/devsecops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

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