Skip to content
Closed
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
76 changes: 76 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: CodeQL

# CodeQL static analysis (SAST) — the source-scanning layer alongside zizmor
# (workflows), scorecard (supply chain), and pip-audit (deps). Alerts land in the
# Security tab. Runs on PUBLIC repos only — the visibility gate skips private forks
# cleanly (drop it if you have GitHub Advanced Security). Multi-language: change the
# matrix `language` for your stack; don't delete the workflow. Delete if unwanted.

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "30 7 * * 1" # weekly, Monday 07:30 UTC (offset from scorecard 05:30 / link-check 06:30)

permissions: {}

jobs:
# Code-scanning upload needs a public repo (or GitHub Advanced Security). Resolve
# visibility via the API — `github.event.repository` is absent on schedule runs, but
# `$GITHUB_REPOSITORY` is always set — so analyze can skip cleanly on private forks.
visibility:
name: Check repo visibility
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read # gh reads repo metadata
outputs:
public: ${{ steps.check.outputs.public }}
steps:
- id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "$(gh api "repos/$GITHUB_REPOSITORY" --jq '.visibility')" = "public" ]; then
echo "public=true" >> "$GITHUB_OUTPUT"
else
echo "public=false" >> "$GITHUB_OUTPUT"
fi

analyze:
name: Analyze (${{ matrix.language }})
needs: visibility
if: needs.visibility.outputs.public == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
security-events: write # upload code-scanning alerts
actions: read # CodeQL reads workflow run metadata
strategy:
fail-fast: false
matrix:
include:
- language: python
build-mode: none # Python isn't compiled
# Node/TS? Uncomment (and enable the Node steps in ci.yml):
# - language: javascript-typescript
# build-mode: none
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3.36.3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# queries: security-extended # deeper suite: more findings, more noise

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3.36.3
with:
category: "/language:${{ matrix.language }}"
30 changes: 27 additions & 3 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Scorecard

# OpenSSF Scorecard — scores the repo's supply-chain security posture and (for a
# PUBLIC repo) publishes results + a badge. Results land in the Security tab.
# Delete this file if you don't want it.
# Private forks skip automatically (the visibility gate below); delete if unwanted.

on:
branch_protection_rule:
Expand All @@ -14,12 +14,36 @@ on:
permissions: {}

jobs:
# Publish + SARIF upload need a public repo. Resolve visibility via the API
# (works on every trigger, unlike the schedule event payload) so a private fork
# skips cleanly. Private repo with GitHub Advanced Security? Drop the gate.
visibility:
name: Check repo visibility
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read # gh reads repo metadata
outputs:
public: ${{ steps.check.outputs.public }}
steps:
- id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "$(gh api "repos/$GITHUB_REPOSITORY" --jq '.visibility')" = "public" ]; then
echo "public=true" >> "$GITHUB_OUTPUT"
else
echo "public=false" >> "$GITHUB_OUTPUT"
fi

analysis:
name: Scorecard analysis
needs: visibility
if: needs.visibility.outputs.public == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read # checkout (required on private forks)
contents: read
security-events: write # upload SARIF to code scanning
id-token: write # publish results to OpenSSF
steps:
Expand All @@ -31,7 +55,7 @@ jobs:
with:
results_file: results.sarif
results_format: sarif
# Needs a PUBLIC repo; set false on a private fork (or delete this workflow).
# Publishes results + badge to OpenSSF (public only; the visibility gate skips private forks).
publish_results: true

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Open a PR from `template-update` so CI runs before the changes land.
|------|----------|
| `.devcontainer/` | Reproducible dev environment — Python 3.12, Node.js LTS, Docker, GitHub CLI, desktop-lite, Claude Code CLI; plus codebase-memory-mcp (structural code graph, best-effort install via `post-create.sh`) |
| `.claude/` | Claude Code configuration — enabled plugins (skills & agents from the grimoire marketplace) and the `/onboard` setup command |
| `.github/` | CI pipeline (active lint incl. workflow security lint via actionlint/zizmor, + Python typecheck/test/build + dependency audit + docs build; Node steps + Docker job commented), Claude Code as CI agent (@claude in issues/PRs), Dependabot auto-patching, publish/release + OpenSSF Scorecard + weekly external-link-check workflows, issue/PR + code-of-conduct + security templates |
| `.github/` | CI pipeline (active lint incl. workflow security lint via actionlint/zizmor, + Python typecheck/test/build + dependency audit + docs build; Node steps + Docker job commented), Claude Code as CI agent (@claude in issues/PRs), Dependabot auto-patching, publish/release + OpenSSF Scorecard + CodeQL code scanning + weekly external-link-check workflows, issue/PR + code-of-conduct + security templates |
| `pyproject.toml` | Python packaging + tool config (ruff, pytest, pyright, codespell) — minimal src-layout stub; rename or delete |
| `src/app/`, `tests/` | Placeholder package (CLI entry point + logging setup, PEP 561 typed) + smoke/logging tests so CI is green on first fork |
| `Makefile`, `.pre-commit-config.yaml` | Task runner (`make lint`/`test`/`check`/`docs`) + the single lint source (ruff, codespell, shellcheck, markdownlint, lychee, actionlint, zizmor, hygiene) that `make lint` and CI both run |
Expand Down Expand Up @@ -69,7 +69,7 @@ If you prefer to set up manually instead of using `/onboard`:
- [ ] Update `.github/dependabot.yml` — remove ecosystems you don't use, add ones you need, adjust directories if not at root
- [ ] Create the `dependency` label — `gh label create dependency --color 0366d6 --description "Dependency updates"` (required by the dependabot and link-check configs)
- [ ] Rename the Python package (`/onboard` does all this; skip the `packages` edit and `python -m build` fails) — set `pyproject.toml` `name` + `description`, rename the `src/app/` directory, update `[tool.hatch.build.targets.wheel]` `packages` to match, update the `app` imports in `src/app/__main__.py` and `tests/` (`from app.log import …` in `__main__.py`/`test_log.py`, `from app.__main__ import …` in `test_smoke.py`), and the `python -m app` references (`__main__.py` `prog=`, `Dockerfile` `CMD` hint).
- [ ] **Not a Python project?** Delete `pyproject.toml`, `src/`, `tests/`, the docs stack (`docs/`, `.readthedocs.yaml.example`, `.github/workflows/pages.yml.example`), `.github/workflows/publish-pypi.yml`, and — if not containerized — `Dockerfile`, `.dockerignore`, `.github/workflows/publish-docker.yml`; adapt `CONTRIBUTING.md` (rewrite the `pip install` setup and the "Requires Python 3.12+" line); trim the `ruff` hook from `.pre-commit-config.yaml` (keep the language-agnostic hooks — codespell, shellcheck, markdownlint, lychee, actionlint, zizmor, hygiene; move codespell's `[tool.codespell]` skip config to a `.codespellrc` before deleting `pyproject.toml`); repoint the `Makefile` targets at your stack's lint/format/typecheck/test/build commands so `make check` stays your one verify gate; in `.github/workflows/ci.yml` remove the `typecheck`/`test`/`build`/`audit`/`docs` jobs (and their `check.needs` + results entries) — the `lint` job just runs pre-commit and stays.
- [ ] **Not a Python project?** Delete `pyproject.toml`, `src/`, `tests/`, the docs stack (`docs/`, `.readthedocs.yaml.example`, `.github/workflows/pages.yml.example`), `.github/workflows/publish-pypi.yml`, and — if not containerized — `Dockerfile`, `.dockerignore`, `.github/workflows/publish-docker.yml`; adapt `CONTRIBUTING.md` (rewrite the `pip install` setup and the "Requires Python 3.12+" line); trim the `ruff` hook from `.pre-commit-config.yaml` (keep the language-agnostic hooks — codespell, shellcheck, markdownlint, lychee, actionlint, zizmor, hygiene; move codespell's `[tool.codespell]` skip config to a `.codespellrc` before deleting `pyproject.toml`); repoint the `Makefile` targets at your stack's lint/format/typecheck/test/build commands so `make check` stays your one verify gate; in `.github/workflows/ci.yml` remove the `typecheck`/`test`/`build`/`audit`/`docs` jobs (and their `check.needs` + results entries) — the `lint` job just runs pre-commit and stays. Keep `.github/workflows/codeql.yml`, switching its matrix `language` (and, for a compiled stack like Go/Java/C++, `build-mode` to `autobuild`) to yours — CodeQL is multi-language, so adapt it rather than delete; delete only if your language isn't among CodeQL's supported set.
- [ ] Replace `tests/test_smoke.py` with real tests — it only exists so the `test` CI job is green out of the box
- [ ] Review `.github/workflows/ci.yml` — the `lint`/`typecheck`/`test`/`build`/`audit`/`docs` jobs are ACTIVE and pass against the shipped stubs. Delete jobs you don't need (and their entries in the `check` aggregator). To enable extras, uncomment the `docker`/`integration-tests` jobs and add each to `check.needs` + the results array; the Node checks are commented *steps inside the `lint` job* (uncomment them there — no `check` change needed)
- [ ] Docs — set `project`/`author`/`project_copyright` in `docs/conf.py`; write the `docs/index.md` landing page (replace the `# Project Docs` title + `TODO(/onboard)`); update the `pip install app` line in `docs/getting-started.md` to the renamed package; after renaming the package, update the `automodule` module names in `docs/reference.md` (`/onboard` does this; the docs build fails if they're left stale)
Expand All @@ -94,8 +94,8 @@ If you prefer to set up manually instead of using `/onboard`:
- **`publish-docker.yml`** — a stub `Dockerfile` is included (give it a real entrypoint). Publishes multi-arch images to `ghcr.io/OWNER/REPO` using the built-in `GITHUB_TOKEN` — no secret needed. Create the `ghcr` Environment (`gh api -X PUT repos/{owner}/{repo}/environments/ghcr`) and add required reviewers to gate image publishing on `v*` tags.
- All trigger on `v*` tags. `publish-pypi.yml` still fails until you rename the package and configure PyPI Trusted Publishing; delete whichever publish workflow (and its stub) you don't need.
- [ ] Enable GitHub Discussions (Settings > General > Features) — issue template config links to it
- [ ] Enable CodeQL default setup (Settings > Security > Code scanning)
- [ ] OpenSSF Scorecard (`.github/workflows/scorecard.yml`) needs a **public** repo to publish its score/badge — delete the workflow if the repo is private
- [ ] CodeQL code scanning ships as `.github/workflows/codeql.yml` (advanced setup, public repos only — private forks skip automatically). Leave GitHub's **default** CodeQL setup OFF (Settings > Security > Code scanning) — the two conflict; enable it only if you first delete the workflow
- [ ] OpenSSF Scorecard (`.github/workflows/scorecard.yml`) needs a **public** repo to publish its score/badge — on a private fork it now skips automatically, so delete it only if you don't want it at all
- [ ] Publish docs (optional) — **GitHub Pages**: set Settings > Pages > Source = "GitHub Actions", then rename `.github/workflows/pages.yml.example` → `pages.yml` (single-version). **Versioned**: rename `.readthedocs.yaml.example` → `.readthedocs.yaml` and import the repo at readthedocs.org. Pick one; the docs *build* is already checked on every PR either way
- [ ] Enable secret scanning with push protection (Settings > Security > Secret Protection)
- [ ] Configure branch ruleset for `main` — require PR reviews, require CI to pass, block force pushes
Expand Down
Loading