castops 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. castops-0.2.1/.github/workflows/deploy-website.yml +44 -0
  2. castops-0.2.1/.github/workflows/devsecops.yml +148 -0
  3. castops-0.2.1/.github/workflows/publish.yml +68 -0
  4. castops-0.2.1/.gitignore +8 -0
  5. castops-0.2.1/CHANGELOG.md +87 -0
  6. castops-0.2.1/CONTRIBUTING.md +279 -0
  7. castops-0.2.1/LICENSE +201 -0
  8. castops-0.2.1/PKG-INFO +381 -0
  9. castops-0.2.1/README.md +365 -0
  10. castops-0.2.1/README.zh.md +332 -0
  11. castops-0.2.1/SECURITY.md +81 -0
  12. castops-0.2.1/TODOS.md +116 -0
  13. castops-0.2.1/dashboard/generate.py +319 -0
  14. castops-0.2.1/dashboard/template.html +290 -0
  15. castops-0.2.1/docs/cli-reference.md +175 -0
  16. castops-0.2.1/docs/dashboard-guide.md +144 -0
  17. castops-0.2.1/docs/getting-started.md +159 -0
  18. castops-0.2.1/docs/gitlab-guide.md +136 -0
  19. castops-0.2.1/docs/pipeline-reference.md +500 -0
  20. castops-0.2.1/docs/plugin-guide.md +269 -0
  21. castops-0.2.1/docs/policy-reference.md +137 -0
  22. castops-0.2.1/docs/zh/cli-reference.md +171 -0
  23. castops-0.2.1/docs/zh/dashboard-guide.md +157 -0
  24. castops-0.2.1/docs/zh/getting-started.md +207 -0
  25. castops-0.2.1/docs/zh/gitlab-guide.md +166 -0
  26. castops-0.2.1/docs/zh/pipeline-reference.md +427 -0
  27. castops-0.2.1/docs/zh/policy-reference.md +201 -0
  28. castops-0.2.1/policy/default.rego +21 -0
  29. castops-0.2.1/policy/permissive.rego +22 -0
  30. castops-0.2.1/policy/strict.rego +34 -0
  31. castops-0.2.1/pyproject.toml +39 -0
  32. castops-0.2.1/setup.cfg +4 -0
  33. castops-0.2.1/src/cast_cli/__init__.py +1 -0
  34. castops-0.2.1/src/cast_cli/detect.py +31 -0
  35. castops-0.2.1/src/cast_cli/install.py +39 -0
  36. castops-0.2.1/src/cast_cli/main.py +145 -0
  37. castops-0.2.1/src/cast_cli/templates/__init__.py +0 -0
  38. castops-0.2.1/src/cast_cli/templates/gitlab/__init__.py +0 -0
  39. castops-0.2.1/src/cast_cli/templates/gitlab/go/__init__.py +0 -0
  40. castops-0.2.1/src/cast_cli/templates/gitlab/go/devsecops.yml +139 -0
  41. castops-0.2.1/src/cast_cli/templates/gitlab/nodejs/__init__.py +0 -0
  42. castops-0.2.1/src/cast_cli/templates/gitlab/nodejs/devsecops.yml +139 -0
  43. castops-0.2.1/src/cast_cli/templates/gitlab/python/__init__.py +0 -0
  44. castops-0.2.1/src/cast_cli/templates/gitlab/python/devsecops.yml +139 -0
  45. castops-0.2.1/src/cast_cli/templates/go/__init__.py +0 -0
  46. castops-0.2.1/src/cast_cli/templates/go/devsecops.yml +202 -0
  47. castops-0.2.1/src/cast_cli/templates/nodejs/__init__.py +0 -0
  48. castops-0.2.1/src/cast_cli/templates/nodejs/devsecops.yml +202 -0
  49. castops-0.2.1/src/cast_cli/templates/python/__init__.py +0 -0
  50. castops-0.2.1/src/cast_cli/templates/python/devsecops.yml +196 -0
  51. castops-0.2.1/src/castops.egg-info/PKG-INFO +381 -0
  52. castops-0.2.1/src/castops.egg-info/SOURCES.txt +83 -0
  53. castops-0.2.1/src/castops.egg-info/dependency_links.txt +1 -0
  54. castops-0.2.1/src/castops.egg-info/entry_points.txt +2 -0
  55. castops-0.2.1/src/castops.egg-info/requires.txt +5 -0
  56. castops-0.2.1/src/castops.egg-info/top_level.txt +1 -0
  57. castops-0.2.1/templates/github/publish-dashboard.yml +83 -0
  58. castops-0.2.1/templates/gitlab/go/devsecops.yml +139 -0
  59. castops-0.2.1/templates/gitlab/nodejs/devsecops.yml +139 -0
  60. castops-0.2.1/templates/gitlab/python/devsecops.yml +139 -0
  61. castops-0.2.1/templates/go/devsecops.yml +202 -0
  62. castops-0.2.1/templates/nodejs/devsecops.yml +202 -0
  63. castops-0.2.1/templates/python/devsecops.yml +196 -0
  64. castops-0.2.1/tests/__init__.py +0 -0
  65. castops-0.2.1/tests/test_cli.py +71 -0
  66. castops-0.2.1/tests/test_dashboard.py +158 -0
  67. castops-0.2.1/tests/test_detect.py +71 -0
  68. castops-0.2.1/tests/test_install.py +113 -0
  69. castops-0.2.1/website/_config.yml +1 -0
  70. castops-0.2.1/website/docs/cli-reference.html +507 -0
  71. castops-0.2.1/website/docs/dashboard-guide.html +415 -0
  72. castops-0.2.1/website/docs/getting-started.html +446 -0
  73. castops-0.2.1/website/docs/gitlab-guide.html +421 -0
  74. castops-0.2.1/website/docs/pipeline-reference.html +811 -0
  75. castops-0.2.1/website/docs/plugin-guide.html +539 -0
  76. castops-0.2.1/website/docs/policy-reference.html +446 -0
  77. castops-0.2.1/website/index.html +779 -0
  78. castops-0.2.1/website/zh/docs/cli-reference.html +507 -0
  79. castops-0.2.1/website/zh/docs/dashboard-guide.html +415 -0
  80. castops-0.2.1/website/zh/docs/getting-started.html +446 -0
  81. castops-0.2.1/website/zh/docs/gitlab-guide.html +421 -0
  82. castops-0.2.1/website/zh/docs/pipeline-reference.html +811 -0
  83. castops-0.2.1/website/zh/docs/plugin-guide.html +539 -0
  84. castops-0.2.1/website/zh/docs/policy-reference.html +446 -0
  85. castops-0.2.1/website/zh/index.html +618 -0
@@ -0,0 +1,44 @@
1
+ # CAST — Deploy official website to GitHub Pages
2
+ #
3
+ # Triggers on push to main (website/ changes).
4
+ # Serves website/ directory at https://castops.github.io/cast/
5
+
6
+ name: Deploy Website
7
+
8
+ on:
9
+ push:
10
+ branches: [main]
11
+ paths:
12
+ - 'website/**'
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+ pages: write
18
+ id-token: write
19
+
20
+ concurrency:
21
+ group: pages
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ deploy:
26
+ name: Deploy to GitHub Pages
27
+ runs-on: ubuntu-latest
28
+ environment:
29
+ name: github-pages
30
+ url: ${{ steps.deployment.outputs.page_url }}
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - name: Setup Pages
35
+ uses: actions/configure-pages@v5
36
+
37
+ - name: Upload artifact
38
+ uses: actions/upload-pages-artifact@v3
39
+ with:
40
+ path: website/
41
+
42
+ - name: Deploy to GitHub Pages
43
+ id: deployment
44
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,148 @@
1
+ # CAST — DevSecOps Pipeline for Python
2
+ # https://github.com/castops/cast
3
+ #
4
+ # Includes:
5
+ # 1. Secrets Detection — Gitleaks
6
+ # 2. SAST — Semgrep
7
+ # 3. SCA — pip-audit
8
+ # 4. Container Security — Trivy (skipped if no Dockerfile)
9
+ # 5. Code Quality — Ruff
10
+ # 6. Security Gate — blocks merge on critical findings
11
+
12
+ name: CAST DevSecOps
13
+
14
+ on:
15
+ push:
16
+ branches: [main, master]
17
+ pull_request:
18
+ branches: [main, master]
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+ security-events: write # required for SARIF upload to GitHub Security tab
24
+ actions: read
25
+
26
+ jobs:
27
+
28
+ # ── 1. Secrets Detection ───────────────────────────────────────────────────
29
+ secrets:
30
+ name: Secrets Detection
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ with:
35
+ fetch-depth: 0 # full history so Gitleaks can scan all commits
36
+ - name: Install Gitleaks
37
+ run: |
38
+ curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.27.2/gitleaks_8.27.2_linux_x64.tar.gz \
39
+ -o /tmp/gitleaks.tar.gz
40
+ tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
41
+ sudo mv /tmp/gitleaks /usr/local/bin/gitleaks
42
+ gitleaks version
43
+ - name: Gitleaks scan
44
+ run: gitleaks detect --source . --verbose --redact
45
+
46
+ # ── 2. SAST ────────────────────────────────────────────────────────────────
47
+ sast:
48
+ name: SAST
49
+ runs-on: ubuntu-latest
50
+ container:
51
+ image: semgrep/semgrep
52
+ steps:
53
+ - uses: actions/checkout@v4
54
+ - name: Semgrep scan
55
+ # SEMGREP_APP_TOKEN is optional — falls back to open-source rules
56
+ run: semgrep ci --sarif --output=semgrep.sarif || true
57
+ env:
58
+ SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
59
+ - name: Ensure SARIF exists
60
+ if: always()
61
+ run: |
62
+ [ -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
63
+ - name: Upload to GitHub Security tab
64
+ uses: github/codeql-action/upload-sarif@v3
65
+ if: always()
66
+ continue-on-error: true # requires GitHub Advanced Security; skip gracefully if not enabled
67
+ with:
68
+ sarif_file: semgrep.sarif
69
+
70
+ # ── 3. SCA — Dependency Audit ──────────────────────────────────────────────
71
+ sca:
72
+ name: SCA
73
+ runs-on: ubuntu-latest
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: actions/setup-python@v5
77
+ with:
78
+ python-version: "3.x"
79
+ cache: pip
80
+ - name: pip-audit
81
+ run: |
82
+ pip install pip-audit
83
+ pip-audit
84
+
85
+ # ── 4. Container Security ──────────────────────────────────────────────────
86
+ container:
87
+ name: Container Security
88
+ runs-on: ubuntu-latest
89
+ steps:
90
+ - uses: actions/checkout@v4
91
+ - name: Check for Dockerfile
92
+ id: check_dockerfile
93
+ run: |
94
+ if [ -f Dockerfile ]; then
95
+ echo "found=true" >> $GITHUB_OUTPUT
96
+ else
97
+ echo "No Dockerfile found — skipping container scan"
98
+ echo "found=false" >> $GITHUB_OUTPUT
99
+ fi
100
+ - name: Build image
101
+ if: steps.check_dockerfile.outputs.found == 'true'
102
+ run: docker build -t cast-scan:${{ github.sha }} .
103
+ - name: Trivy scan
104
+ if: steps.check_dockerfile.outputs.found == 'true'
105
+ uses: aquasecurity/trivy-action@master
106
+ with:
107
+ image-ref: cast-scan:${{ github.sha }}
108
+ format: sarif
109
+ output: trivy.sarif
110
+ severity: CRITICAL,HIGH
111
+ exit-code: "0" # gate handles blocking, not trivy directly
112
+ - name: Upload to GitHub Security tab
113
+ if: steps.check_dockerfile.outputs.found == 'true'
114
+ uses: github/codeql-action/upload-sarif@v3
115
+ continue-on-error: true # requires GitHub Advanced Security; skip gracefully if not enabled
116
+ with:
117
+ sarif_file: trivy.sarif
118
+
119
+ # ── 5. Code Quality ────────────────────────────────────────────────────────
120
+ quality:
121
+ name: Code Quality
122
+ runs-on: ubuntu-latest
123
+ steps:
124
+ - uses: actions/checkout@v4
125
+ - uses: astral-sh/ruff-action@v1
126
+
127
+ # ── 6. Security Gate ───────────────────────────────────────────────────────
128
+ gate:
129
+ name: Security Gate
130
+ runs-on: ubuntu-latest
131
+ needs: [secrets, sast, sca, quality]
132
+ if: always()
133
+ steps:
134
+ - name: Evaluate results
135
+ run: |
136
+ echo "secrets : ${{ needs.secrets.result }}"
137
+ echo "sast : ${{ needs.sast.result }}"
138
+ echo "sca : ${{ needs.sca.result }}"
139
+ echo "quality : ${{ needs.quality.result }}"
140
+
141
+ if [[ "${{ needs.secrets.result }}" == "failure" ||
142
+ "${{ needs.sast.result }}" == "failure" ||
143
+ "${{ needs.sca.result }}" == "failure" ]]; then
144
+ echo "❌ Security gate failed — merge blocked"
145
+ exit 1
146
+ fi
147
+
148
+ echo "✅ All checks passed — safe to merge"
@@ -0,0 +1,68 @@
1
+ # CAST — Publish castops to PyPI
2
+ #
3
+ # Triggers on push of a version tag (e.g. v0.2.0).
4
+ # Uses PyPI Trusted Publishing (OIDC) — no API token needed.
5
+ #
6
+ # One-time setup required on PyPI before first run:
7
+ # pypi.org → Manage account → Publishing → Add a new publisher
8
+ # Publisher: GitHub | Owner: castops | Repo: cast
9
+ # Workflow: publish.yml | Environment: pypi
10
+
11
+ name: Publish to PyPI
12
+
13
+ on:
14
+ push:
15
+ tags:
16
+ - 'v*'
17
+ workflow_dispatch:
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ jobs:
23
+ build:
24
+ name: Build distribution
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ with:
29
+ fetch-depth: 0 # setuptools-scm needs full history for version
30
+
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: '3.11'
34
+
35
+ - name: Install build
36
+ run: pip install build
37
+
38
+ - name: Build sdist and wheel
39
+ run: |
40
+ # Strip leading 'v' from tag (v0.2.1 → 0.2.1) so PyPI gets a clean version.
41
+ # SETUPTOOLS_SCM_PRETEND_VERSION overrides the git-derived version entirely.
42
+ VERSION="${GITHUB_REF_NAME#v}"
43
+ SETUPTOOLS_SCM_PRETEND_VERSION="$VERSION" python -m build
44
+
45
+ - name: Upload build artifacts
46
+ uses: actions/upload-artifact@v4
47
+ with:
48
+ name: dist
49
+ path: dist/
50
+
51
+ publish:
52
+ name: Publish to PyPI
53
+ needs: build
54
+ runs-on: ubuntu-latest
55
+ environment:
56
+ name: pypi
57
+ url: https://pypi.org/project/castops/
58
+ permissions:
59
+ id-token: write # required for OIDC trusted publishing
60
+ steps:
61
+ - name: Download build artifacts
62
+ uses: actions/download-artifact@v4
63
+ with:
64
+ name: dist
65
+ path: dist/
66
+
67
+ - name: Publish to PyPI
68
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ src/*.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ .gstack/
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to CAST are documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ---
9
+
10
+ ## [Unreleased]
11
+
12
+ ### Added
13
+
14
+ - **Node.js and Go GitHub Actions templates** — production-ready pipelines for both stacks:
15
+ - Node.js: Gitleaks + Semgrep + npm audit + Trivy + ESLint + conftest gate
16
+ - Go: Gitleaks + Semgrep + govulncheck + Trivy + staticcheck + conftest gate
17
+ - **GitLab CI templates** — full security parity with GitHub Actions for Python, Node.js, and Go:
18
+ - Use `cast init --platform gitlab` to generate a `.gitlab-ci.yml`
19
+ - Findings appear in GitLab's Security dashboard via SARIF artifact reports
20
+ - **Policy as Code (OPA/conftest)** — the security gate now evaluates SARIF findings using
21
+ Rego policies instead of hardcoded shell logic:
22
+ - `policy/default.rego` — blocks on CRITICAL findings (default)
23
+ - `policy/strict.rego` — blocks on HIGH + CRITICAL
24
+ - `policy/permissive.rego` — audit only, never blocks merges
25
+ - Custom policies can be placed in a `policy/` directory alongside the workflow
26
+ - **Static HTML security dashboard** — generate a compliance overview from SARIF results:
27
+ - `dashboard/generate.py`: parses SARIF files and renders a zero-dependency HTML page
28
+ - Red/green status per scan, collapsible finding details, commit SHA and timestamp
29
+ - Deploy to GitHub Pages with `templates/github/publish-dashboard.yml`
30
+ - **`cast init --platform gitlab`** — the CLI now supports GitLab CI as a target platform
31
+ - **Auto-detection of CI platform** — `cast init` detects `.gitlab-ci.yml` and `.github/`
32
+ to determine the platform automatically
33
+ - **Chinese documentation** — full Chinese translation under `docs/zh/` and `README.zh.md`
34
+ - **Test suite** — 65 tests covering project detection, template installation, dashboard
35
+ generation, and CLI behavior
36
+
37
+ ### Fixed
38
+
39
+ - **Gitleaks in org repositories** — replaced the GitHub Action (requires paid org license)
40
+ with direct CLI installation from GitHub releases; works on all repositories for free
41
+ - **SARIF upload without GitHub Advanced Security** — upload steps now use `continue-on-error`
42
+ so the pipeline does not fail when GHAS is not enabled on the repository
43
+ - **Semgrep SARIF fallback** — added an "Ensure SARIF exists" step so the upload action
44
+ never fails when Semgrep exits non-zero without creating a SARIF file
45
+ - **Auto-detection priority** — Go and Node.js are now detected before Python, so repositories
46
+ that use `pyproject.toml` only for tooling (Ruff, pre-commit) are not misidentified
47
+
48
+ ---
49
+
50
+ ## [0.1.0] — 2024-01-01
51
+
52
+ ### Added
53
+
54
+ - **`cast` CLI** — new `castops` Python package installable via `pip install castops`
55
+ - `cast init` command: writes a DevSecOps workflow to `.github/workflows/devsecops.yml`
56
+ - `cast version` command: displays the installed package version
57
+ - Auto-detection of project type from marker files (`pyproject.toml`, `requirements.txt`, etc.)
58
+ - `--force` flag to overwrite existing workflow files
59
+ - `--type` flag to override auto-detection
60
+ - Rich terminal output with color-coded status messages
61
+ - **Python DevSecOps template** — production-ready GitHub Actions workflow including:
62
+ - Secrets Detection via [Gitleaks](https://github.com/gitleaks/gitleaks) (full git history scan)
63
+ - SAST via [Semgrep](https://semgrep.dev) with SARIF upload to GitHub Security tab
64
+ - SCA via [pip-audit](https://pypi.org/project/pip-audit/) for vulnerable dependency detection
65
+ - Container Security via [Trivy](https://trivy.dev) (conditional on Dockerfile presence)
66
+ - Code Quality via [Ruff](https://docs.astral.sh/ruff/)
67
+ - Security Gate job that blocks merges on critical security failures
68
+ - **Manual installation** support via `curl` for teams that prefer not to install the CLI
69
+
70
+ ### Technical Details
71
+
72
+ - Python 3.9+ support
73
+ - Templates embedded in the package via `importlib.resources` for offline use
74
+ - MIT-compatible dependencies: [Typer](https://typer.tiangolo.com/) and [Rich](https://rich.readthedocs.io/)
75
+ - Build system: `setuptools` + `setuptools-scm` (version from git tags)
76
+
77
+ ---
78
+
79
+ ## [0.0.1] — Initial Commit
80
+
81
+ - Project scaffolding and initial Python workflow template
82
+ - Apache 2.0 license
83
+
84
+ ---
85
+
86
+ [Unreleased]: https://github.com/castops/cast/compare/v0.1.0...HEAD
87
+ [0.1.0]: https://github.com/castops/cast/releases/tag/v0.1.0
@@ -0,0 +1,279 @@
1
+ # Contributing to CAST
2
+
3
+ Thank you for your interest in contributing to CAST. This document outlines the process
4
+ for contributing code, templates, and documentation to the project.
5
+
6
+ ## Table of Contents
7
+
8
+ - [Code of Conduct](#code-of-conduct)
9
+ - [Getting Started](#getting-started)
10
+ - [Development Setup](#development-setup)
11
+ - [Project Structure](#project-structure)
12
+ - [Adding a New Template](#adding-a-new-template)
13
+ - [Running Tests](#running-tests)
14
+ - [Submitting a Pull Request](#submitting-a-pull-request)
15
+ - [Release Process](#release-process)
16
+
17
+ ---
18
+
19
+ ## Code of Conduct
20
+
21
+ This project follows a standard open-source code of conduct. Be respectful, constructive,
22
+ and collaborative. Harassment of any kind will not be tolerated.
23
+
24
+ ---
25
+
26
+ ## Getting Started
27
+
28
+ Before contributing, please:
29
+
30
+ 1. **Search existing issues** to avoid duplicates
31
+ 2. **Open an issue** for non-trivial changes to discuss the approach before writing code
32
+ 3. **Fork the repository** and create a feature branch from `main`
33
+
34
+ ---
35
+
36
+ ## Development Setup
37
+
38
+ ### Prerequisites
39
+
40
+ - Python 3.9 or higher
41
+ - `git`
42
+
43
+ ### Install in Editable Mode
44
+
45
+ ```bash
46
+ # Clone your fork
47
+ git clone https://github.com/<your-username>/cast.git
48
+ cd cast
49
+
50
+ # Create and activate a virtual environment
51
+ python -m venv .venv
52
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
53
+
54
+ # Install in editable mode with dev dependencies
55
+ pip install -e ".[dev]"
56
+ ```
57
+
58
+ > If there is no `[dev]` extras group yet, install the base package with:
59
+ > ```bash
60
+ > pip install -e .
61
+ > ```
62
+
63
+ ### Verify Installation
64
+
65
+ ```bash
66
+ cast version
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Project Structure
72
+
73
+ ```
74
+ cast/
75
+ ├── src/
76
+ │ └── cast_cli/
77
+ │ ├── __init__.py
78
+ │ ├── main.py # CLI entry point — Typer app, all commands
79
+ │ ├── detect.py # Project type auto-detection
80
+ │ ├── install.py # Template fetching and writing
81
+ │ └── templates/
82
+ │ ├── python/devsecops.yml # Embedded GitHub Actions templates
83
+ │ ├── nodejs/devsecops.yml
84
+ │ ├── go/devsecops.yml
85
+ │ └── gitlab/
86
+ │ ├── python/devsecops.yml # Embedded GitLab CI templates
87
+ │ ├── nodejs/devsecops.yml
88
+ │ └── go/devsecops.yml
89
+ ├── templates/
90
+ │ ├── python/devsecops.yml # Source GitHub Actions templates
91
+ │ ├── nodejs/devsecops.yml # (must stay in sync with embedded copies above)
92
+ │ ├── go/devsecops.yml
93
+ │ ├── gitlab/
94
+ │ │ ├── python/devsecops.yml # Source GitLab CI templates
95
+ │ │ ├── nodejs/devsecops.yml
96
+ │ │ └── go/devsecops.yml
97
+ │ └── github/
98
+ │ └── publish-dashboard.yml # GitHub Pages dashboard workflow
99
+ ├── dashboard/
100
+ │ ├── generate.py # SARIF → static HTML dashboard generator
101
+ │ └── template.html # Dashboard HTML/CSS template
102
+ ├── policy/
103
+ │ ├── default.rego # OPA policy: block on CRITICAL
104
+ │ ├── strict.rego # OPA policy: block on HIGH + CRITICAL
105
+ │ └── permissive.rego # OPA policy: audit only, never block
106
+ ├── docs/
107
+ │ ├── getting-started.md
108
+ │ ├── cli-reference.md
109
+ │ ├── pipeline-reference.md
110
+ │ ├── policy-reference.md
111
+ │ ├── dashboard-guide.md
112
+ │ ├── gitlab-guide.md
113
+ │ └── zh/ # Chinese documentation
114
+ ├── tests/
115
+ │ ├── test_detect.py
116
+ │ ├── test_install.py
117
+ │ ├── test_dashboard.py
118
+ │ └── test_cli.py
119
+ ├── pyproject.toml
120
+ ├── README.md
121
+ ├── README.zh.md
122
+ ├── CONTRIBUTING.md
123
+ ├── CHANGELOG.md
124
+ └── SECURITY.md
125
+ ```
126
+
127
+ ### Key Design Decisions
128
+
129
+ | Decision | Rationale |
130
+ |----------|-----------|
131
+ | Templates are **embedded** in the package (`src/cast_cli/templates/`) | Ensures `cast init` works offline and without network calls at install time |
132
+ | Templates also exist at **top-level** (`templates/`) | Allows direct `curl` access for manual installation without the CLI |
133
+ | **Auto-detection** before explicit `--type` | Reduces friction for the happy path |
134
+ | **`--force` flag** required to overwrite | Prevents accidental overwrites of customized workflows |
135
+
136
+ ---
137
+
138
+ ## Adding a New Template
139
+
140
+ To add support for a new language or framework, follow these steps:
141
+
142
+ ### 1. Create the workflow template
143
+
144
+ Create the file at both paths (they must be identical):
145
+
146
+ ```
147
+ templates/<stack>/devsecops.yml
148
+ src/cast_cli/templates/<stack>/devsecops.yml
149
+ ```
150
+
151
+ A template must:
152
+
153
+ - Follow the CAST naming convention (`name: CAST DevSecOps`)
154
+ - Run on `push` and `pull_request` to `main`/`master`
155
+ - Include at minimum: secrets detection, SAST, and SCA
156
+ - Upload all SARIF results to GitHub Security tab
157
+ - Include a `gate` job that blocks merges on critical failures
158
+
159
+ Use the existing `templates/python/devsecops.yml` as a reference implementation.
160
+
161
+ ### 2. Register the marker files
162
+
163
+ In `src/cast_cli/detect.py`, add your stack's marker files to the `MARKERS` dict.
164
+ Order matters — entries listed first win in monorepos:
165
+
166
+ ```python
167
+ MARKERS: dict[str, list[str]] = {
168
+ "go": ["go.mod"],
169
+ "nodejs": ["package.json"],
170
+ "python": ["pyproject.toml", "requirements.txt", "setup.py", "setup.cfg"],
171
+ "<stack>": ["<marker-file>"], # add your stack here
172
+ }
173
+ ```
174
+
175
+ ### 3. Register the supported type
176
+
177
+ In `src/cast_cli/install.py`, add your stack to the `SUPPORTED` set:
178
+
179
+ ```python
180
+ SUPPORTED: set[str] = {"python", "nodejs", "go", "<stack>"}
181
+ ```
182
+
183
+ ### 4. Update documentation
184
+
185
+ - Add the new stack to the **Templates** table in `README.md`
186
+ - Add an entry in `CHANGELOG.md` under the appropriate version
187
+ - Add the stack description to `SUPPORTED_TYPES` in `main.py`
188
+
189
+ ### 5. Test manually
190
+
191
+ ```bash
192
+ # Create a temporary test directory with a marker file
193
+ mkdir /tmp/test-<stack> && cd /tmp/test-<stack>
194
+ touch <marker-file>
195
+
196
+ # Run cast init and verify the workflow is created
197
+ cast init
198
+ cat .github/workflows/devsecops.yml
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Running Tests
204
+
205
+ ```bash
206
+ # Run all tests
207
+ pytest
208
+
209
+ # Run with coverage
210
+ pytest --cov=cast_cli
211
+ ```
212
+
213
+ > New contributions should include tests for any new detection logic, CLI behavior,
214
+ > or template changes. The test suite covers `detect`, `install`, `dashboard`, and CLI.
215
+
216
+ ---
217
+
218
+ ## Code Style
219
+
220
+ CAST uses [Ruff](https://docs.astral.sh/ruff/) for linting and formatting.
221
+
222
+ ```bash
223
+ # Check for lint issues
224
+ ruff check src/
225
+
226
+ # Auto-fix issues
227
+ ruff check --fix src/
228
+
229
+ # Format code
230
+ ruff format src/
231
+ ```
232
+
233
+ All code must pass `ruff check` with no errors before a pull request can be merged.
234
+
235
+ ---
236
+
237
+ ## Submitting a Pull Request
238
+
239
+ 1. **Create a feature branch** from `main`:
240
+ ```bash
241
+ git checkout -b feat/nodejs-template
242
+ ```
243
+
244
+ 2. **Make your changes** following the guidelines in this document
245
+
246
+ 3. **Test your changes** manually and with the test suite
247
+
248
+ 4. **Update the changelog** in `CHANGELOG.md` under `[Unreleased]`
249
+
250
+ 5. **Push and open a PR** against `main`:
251
+ ```bash
252
+ git push origin feat/nodejs-template
253
+ ```
254
+
255
+ ### Pull Request Checklist
256
+
257
+ - [ ] Changes are limited to a single concern
258
+ - [ ] Code passes `ruff check` with no errors
259
+ - [ ] Manual testing completed
260
+ - [ ] `CHANGELOG.md` updated
261
+ - [ ] Documentation updated (README, docstrings)
262
+
263
+ ---
264
+
265
+ ## Release Process
266
+
267
+ Releases are managed by maintainers. The process:
268
+
269
+ 1. Update `CHANGELOG.md` — move items from `[Unreleased]` to a new version section
270
+ 2. Create and push a version tag: `git tag v0.x.0 && git push origin v0.x.0`
271
+ 3. `setuptools-scm` reads the tag to set the package version automatically
272
+ 4. The package is built and published to PyPI via CI
273
+
274
+ ---
275
+
276
+ ## Questions?
277
+
278
+ Open a [GitHub Discussion](https://github.com/castops/cast/discussions) or file an
279
+ [issue](https://github.com/castops/cast/issues).