Skip to content

ci: solo-dev tooling bundle (zizmor, codeql, lychee, typos, deptry+vulture, mutmut, ADRs, OSSInsight) - #325

Merged
robotrocketscience merged 12 commits into
mainfrom
ci/devtools-bundle
Apr 30, 2026
Merged

ci: solo-dev tooling bundle (zizmor, codeql, lychee, typos, deptry+vulture, mutmut, ADRs, OSSInsight)#325
robotrocketscience merged 12 commits into
mainfrom
ci/devtools-bundle

Conversation

@yoshi280

@yoshi280 yoshi280 commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds eight tools to fill the solo-dev tooling gaps surfaced in audit. One commit per tool plus a gate: summary commit.

Tool Trigger Purpose
zizmor workflow changes + weekly cron static lint of .github/workflows/ (broad token scopes, script-injection, unpinned actions) → SARIF
CodeQL push/PR + weekly cron python + actions SAST, security-extended queries → SARIF
lychee weekly cron broken-link detector across all .md/.rst; opens issue on failure
typos PR spell-check identifiers, comments, docs (config in .typos.toml)
deptry PR + push undeclared/unused/transitive deps relative to pyproject.toml
vulture PR + push (advisory) unreachable functions/classes; min-confidence 80
mutmut weekly cron mutation testing; report as 30-day artifact
OSSInsight README badge linking to hosted analytics
ADRs docs/adr/ with template + 0001 (record-decisions) + 0002 (two-repo-separation)

Codecov skipped per [user] decision (no token configured).
Trivy skipped — March 2026 supply-chain compromise.

All new workflows include step-security/harden-runner@v2 in audit mode.

Test plan

  • CI passes on this PR (typos, deadcode workflows run)
  • After merge: zizmor and CodeQL run on next push to main; SARIF lands in Security tab
  • After merge: verify CodeQL actions language pack initializes (matrix entry succeeds on first run; if it fails the fix is dropping it from the matrix in a follow-up)
  • After Renovate's first run: floating tags (@v4, @v5, @master) get rewritten to SHAs in a digest-pinning PR

Follow-ups

  • Harden-Runner expansion to existing workflows: see #TBD (ci/harden-runner-expansion branch)
  • First mutmut run will be slow (~1–4h); consider triggering manually via workflow_dispatch before relying on the cron

Summary by Sourcery

Add additional CI workflows for code quality, security, and mutation testing, introduce ADR documentation, and expose repository analytics via an OSSInsight badge.

New Features:

  • Add OSSInsight analytics badge to the project README.
  • Introduce Architecture Decision Records under docs/adr/, including an ADR index, template, and two initial decisions documenting ADR usage and repo separation.

Enhancements:

  • Add GitHub Actions workflows for dependency and dead code analysis using deptry and vulture.
  • Add a scheduled link-check workflow using lychee that files issues for detected broken links.
  • Add a scheduled mutation testing workflow using mutmut with results uploaded as artifacts.
  • Add a zizmor workflow to statically analyze GitHub workflows and upload SARIF results.
  • Add a CodeQL workflow to run security analysis for Python code and GitHub Actions definitions.
  • Add a spell-checking workflow using typos for pull requests.
  • Configure typos via .typos.toml to tune ignored files, patterns, and project-specific words.

@sourcery-ai

sourcery-ai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a CI "solo-dev tooling" bundle: new GitHub Actions workflows for security/static analysis (zizmor, CodeQL), dependency/dead-code checks (deptry, vulture), link checking (lychee), spell checking (typos), and mutation testing (mutmut), plus an ADR system and an OSSInsight analytics badge in the README.

Sequence diagram for the new lychee link-check workflow

sequenceDiagram
  actor Dev as Developer
  participant Repo as GitHub_repo
  participant Scheduler as Cron_scheduler
  participant WF as link-check_workflow
  participant Lychee as lychee_action
  participant Issues as GitHub_issues

  Scheduler->>WF: Trigger on cron (Mon 14:00 UTC)
  Dev->>WF: Optional workflow_dispatch

  WF->>Repo: actions/checkout@v4
  WF->>Lychee: Run lycheeverse/lychee-action@v2 with args
  Lychee-->>WF: exit_code, report_file(lychee/out.md)

  alt exit_code != 0
    WF->>Issues: create-issue-from-file@v5
    Issues-->>WF: Issue created (title link-check: broken links detected)
  else exit_code == 0
    WF-->>WF: No issue created
  end
Loading

Flow diagram for ADR authoring and evolution

flowchart TD
  Start[Identify_non_obvious_architecture_decision] --> CheckNeed{Needs_long_term_rationale?}

  CheckNeed -- No --> Skip[Document_only_in_PR_or_commit]
  CheckNeed -- Yes --> Template[Copy_docs/adr/template.md_to_new_file]

  Template --> Number[Assign_next_monotonic_number_NNNN]
  Number --> Edit[Fill_in_Context_Decision_Alternatives_Consequences]
  Edit --> Commit[Commit_ADR_under_docs/adr]
  Commit --> Merge[Merge_to_main_branch]

  Merge --> Use[Refer_to_ADR_in_future_changes]

  Use --> Supersede{Decision_superseded?}
  Supersede -- No --> End[Keep_ADR_append_only]
  Supersede -- Yes --> NewADR[Create_new_ADR_linking_to_old]
  NewADR --> End
Loading

File-Level Changes

Change Details Files
Introduce deptry and vulture dead-code/dependency analysis workflow for pushes and PRs.
  • Add deadcode GitHub Actions workflow triggered on push and pull_request to main
  • Configure deptry job using uvx to analyze the src directory for dependency issues
  • Configure vulture job using uvx to scan src for unreachable code with min-confidence 80
  • Apply step-security/harden-runner and uv caching to both jobs
.github/workflows/deadcode.yml
Add scheduled link-check workflow using lychee that opens issues on broken links.
  • Create link-check workflow triggered weekly via cron and manually via workflow_dispatch
  • Run lycheeverse/lychee-action across Markdown and reStructuredText files with tuned args and non-failing exit code
  • On non-zero lychee exit code, create an issue from generated report with docs-related labels
  • Set appropriate contents/issues permissions, concurrency group, and harden-runner step
.github/workflows/link-check.yml
Add scheduled mutation testing workflow using mutmut with artifacted results.
  • Create mutation workflow triggered weekly via cron and manually via workflow_dispatch
  • Install and run mutmut via uv against src/aelfrice with tests in tests, tolerating failures
  • Generate and print mutation-report.txt and upload it as a 30-day artifact
  • Configure long timeout, permissions, concurrency, uv sync with dev+archive extras, and harden-runner
.github/workflows/mutation.yml
Introduce zizmor workflow security linter with SARIF upload to Security tab.
  • Create zizmor workflow triggered by workflow/action path changes on PRs, pushes to main, and weekly cron
  • Run zizmor via uvx to produce SARIF output for GitHub workflows and actions
  • Upload zizmor SARIF using github/codeql-action/upload-sarif with a custom category
  • Configure minimal permissions, concurrency, and harden-runner setup
.github/workflows/zizmor.yml
Add CodeQL SAST workflow for Python and GitHub Actions with security-extended queries.
  • Create CodeQL workflow triggered on push, pull_request to main, and weekly cron
  • Define matrix over languages python and actions with fail-fast disabled
  • Initialize CodeQL with security-extended and security-and-quality query packs and analyze per language
  • Configure security-events write permission, concurrency control, and harden-runner
.github/workflows/codeql.yml
Introduce spell-checking via typos on PRs with repository-specific configuration.
  • Add typos workflow triggered on pull_request to main to run crate-ci/typos
  • Apply harden-runner and checkout steps before running the typos action
  • Create .typos.toml to ignore hash-like identifiers and specific paths (locks, telemetry, test data, changelog)
  • Extend dictionary to accept project-specific terms like aelfrice and aelf
.github/workflows/typos.yml
.typos.toml
Establish ADR system with initial decisions and template documentation.
  • Create docs/adr/README.md describing ADR purpose, index, format, and when to write one
  • Add ADR 0001 documenting the decision to adopt lightweight Nygard-style ADRs stored in-repo
  • Add ADR 0002 documenting two-repo physical separation for public/private boundary and its consequences
  • Provide a generic ADR markdown template for future records
docs/adr/README.md
docs/adr/0001-record-architecture-decisions.md
docs/adr/0002-two-repo-physical-separation.md
docs/adr/template.md
Add OSSInsight analytics badge to project README.
  • Insert OSSInsight badge linking to hosted analytics in the README badge section
  • Keep existing CI, license, and Python version badges unchanged
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@robotrocketscience has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 22 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6358f035-dbae-4068-bbd0-6c44cb968c27

📥 Commits

Reviewing files that changed from the base of the PR and between 94d6de3 and 1531a8e.

📒 Files selected for processing (13)
  • .github/workflows/codeql.yml
  • .github/workflows/deadcode.yml
  • .github/workflows/link-check.yml
  • .github/workflows/mutation.yml
  • .github/workflows/typos.yml
  • .github/workflows/zizmor.yml
  • .typos.toml
  • README.md
  • docs/adr/0001-record-architecture-decisions.md
  • docs/adr/0002-two-repo-physical-separation.md
  • docs/adr/README.md
  • docs/adr/template.md
  • pyproject.toml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/devtools-bundle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 22 minutes and 22 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zizmor found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

matrix:
language: [python, actions]
steps:
- uses: step-security/harden-runner@v2
deptry:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
vulture:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
egress-policy: audit
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
typos:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- uses: actions/checkout@v4
- uses: crate-ci/typos@master
zizmor:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • The typos workflow uses crate-ci/typos@master while the rest of the CI favors pinned or versioned actions; consider switching this to a tagged release or SHA so it aligns with your digest-pinning policy and avoids unexpected breaking changes.
  • In link-check.yml, create-issue-from-file assumes ./lychee/out.md exists; double-check that the lychee action is configured to actually write that file (and in the expected format) or add an explicit output path to avoid silent failures when creating issues.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `typos` workflow uses `crate-ci/typos@master` while the rest of the CI favors pinned or versioned actions; consider switching this to a tagged release or SHA so it aligns with your digest-pinning policy and avoids unexpected breaking changes.
- In `link-check.yml`, `create-issue-from-file` assumes `./lychee/out.md` exists; double-check that the lychee action is configured to actually write that file (and in the expected format) or add an explicit output path to avoid silent failures when creating issues.

## Individual Comments

### Comment 1
<location path=".github/workflows/mutation.yml" line_range="32-37" />
<code_context>
+      - run: uv sync --frozen --extra dev --extra archive
+      - name: Install mutmut
+        run: uv pip install mutmut
+      - name: Run mutation tests
+        id: mutmut
+        run: |
+          uv run mutmut run --paths-to-mutate=src/aelfrice --tests-dir=tests || true
+          uv run mutmut results > mutation-report.txt
+          cat mutation-report.txt
+      - uses: actions/upload-artifact@v4
+        with:
</code_context>
<issue_to_address>
**issue (bug_risk):** The `mutmut results` command can fail and cause the job to fail even though `mutmut run` is guarded with `|| true`.

Only `mutmut run` is guarded with `|| true`; `uv run mutmut results > mutation-report.txt` can still exit non‑zero if no results are produced, causing the step to fail. If this job is meant to be non‑blocking, either guard the `mutmut results` call as well, wrap both commands in a script that always exits 0, or mark the step with `continue-on-error: true` so failures here don’t break the workflow.
</issue_to_address>

### Comment 2
<location path="docs/adr/0002-two-repo-physical-separation.md" line_range="11" />
<code_context>
+
+aelfrice is developed alongside private artifacts: research notes, planning documents, LLC/business records, experiment data, draft posts. The product code is open-source and ships to PyPI; the surrounding workspace is not.
+
+Earlier the project tried a single-repo "filter on publish" pipeline: a quarantine staging area, allowlist (`.github-include`), gitleaks rules, and a publish script that filtered private content out before pushing to GitHub. This pipeline was complex, easy to mis-configure, and a single allowlist typo could leak private content irreversibly — git history is hard to scrub once pushed, and `refs/pull/N/head` pins commits permanently.
+
+## Decision
</code_context>
<issue_to_address>
**nitpick (typo):** Consider changing "mis-configure" to the more standard "misconfigure".

The hyphenated form is rarely used in technical writing; the standard spelling is "misconfigure," which also improves flow.

```suggestion
Earlier the project tried a single-repo "filter on publish" pipeline: a quarantine staging area, allowlist (`.github-include`), gitleaks rules, and a publish script that filtered private content out before pushing to GitHub. This pipeline was complex, easy to misconfigure, and a single allowlist typo could leak private content irreversibly — git history is hard to scrub once pushed, and `refs/pull/N/head` pins commits permanently.
```
</issue_to_address>

### Comment 3
<location path="docs/adr/0002-two-repo-physical-separation.md" line_range="18" />
<code_context>
+Use **two physically separate repositories** with no path between them:
+
+- `~/projects/aelfrice` — public product code. Origin is GitHub only.
+- `~/projects/aelfrice-lab` — private workspace. Origin is a self-hosted gitea only. A pre-push hook rejects any remote URL containing `github.com`.
+
+The boundary is the directory of origin, not a transformation. Test fixtures, paraphrased examples, and "abstracted" content all count as derived from their source directory.
</code_context>
<issue_to_address>
**suggestion (typo):** Capitalize "Gitea" as a proper noun.

As a product name, this should be capitalized as “self-hosted Gitea.”

```suggestion
- `~/projects/aelfrice-lab` — private workspace. Origin is a self-hosted Gitea only. A pre-push hook rejects any remote URL containing `github.com`.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +32 to +37
- name: Run mutation tests
id: mutmut
run: |
uv run mutmut run --paths-to-mutate=src/aelfrice --tests-dir=tests || true
uv run mutmut results > mutation-report.txt
cat mutation-report.txt

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The mutmut results command can fail and cause the job to fail even though mutmut run is guarded with || true.

Only mutmut run is guarded with || true; uv run mutmut results > mutation-report.txt can still exit non‑zero if no results are produced, causing the step to fail. If this job is meant to be non‑blocking, either guard the mutmut results call as well, wrap both commands in a script that always exits 0, or mark the step with continue-on-error: true so failures here don’t break the workflow.


aelfrice is developed alongside private artifacts: research notes, planning documents, LLC/business records, experiment data, draft posts. The product code is open-source and ships to PyPI; the surrounding workspace is not.

Earlier the project tried a single-repo "filter on publish" pipeline: a quarantine staging area, allowlist (`.github-include`), gitleaks rules, and a publish script that filtered private content out before pushing to GitHub. This pipeline was complex, easy to mis-configure, and a single allowlist typo could leak private content irreversibly — git history is hard to scrub once pushed, and `refs/pull/N/head` pins commits permanently.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): Consider changing "mis-configure" to the more standard "misconfigure".

The hyphenated form is rarely used in technical writing; the standard spelling is "misconfigure," which also improves flow.

Suggested change
Earlier the project tried a single-repo "filter on publish" pipeline: a quarantine staging area, allowlist (`.github-include`), gitleaks rules, and a publish script that filtered private content out before pushing to GitHub. This pipeline was complex, easy to mis-configure, and a single allowlist typo could leak private content irreversibly — git history is hard to scrub once pushed, and `refs/pull/N/head` pins commits permanently.
Earlier the project tried a single-repo "filter on publish" pipeline: a quarantine staging area, allowlist (`.github-include`), gitleaks rules, and a publish script that filtered private content out before pushing to GitHub. This pipeline was complex, easy to misconfigure, and a single allowlist typo could leak private content irreversibly — git history is hard to scrub once pushed, and `refs/pull/N/head` pins commits permanently.

Use **two physically separate repositories** with no path between them:

- `~/projects/aelfrice` — public product code. Origin is GitHub only.
- `~/projects/aelfrice-lab` — private workspace. Origin is a self-hosted gitea only. A pre-push hook rejects any remote URL containing `github.com`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Capitalize "Gitea" as a proper noun.

As a product name, this should be capitalized as “self-hosted Gitea.”

Suggested change
- `~/projects/aelfrice-lab` — private workspace. Origin is a self-hosted gitea only. A pre-push hook rejects any remote URL containing `github.com`.
- `~/projects/aelfrice-lab` — private workspace. Origin is a self-hosted Gitea only. A pre-push hook rejects any remote URL containing `github.com`.

@github-actions
github-actions Bot force-pushed the ci/devtools-bundle branch 2 times, most recently from 62c3519 to cdb97ad Compare April 30, 2026 22:02
@yoshi280

Copy link
Copy Markdown
Collaborator Author

[claim:review:Toug:2026-04-30T22:18:13Z]

@yoshi280

Copy link
Copy Markdown
Collaborator Author

Review: blocking on action-pinning regressions and a likely-broken issue-creation step. Test-plan items 1 and 2 also can't be evaluated until the required CI surface actually runs on this PR.

Blockers

  1. Pinning regresses the work in feat: per-turn hook audit log (#280 mitigation 3) #314 / commit 6353181. That commit SHA-pinned step-security/harden-runner to v2.19.0 across every existing workflow. All six new workflows here re-introduce the floating @v2 tag for harden-runner, plus floating tags on every other third-party action (actions/checkout@v4, astral-sh/setup-uv@v5, github/codeql-action/*@v3, lycheeverse/lychee-action@v2, peter-evans/create-issue-from-file@v5, actions/upload-artifact@v4). Most concerning: .github/workflows/typos.yml uses crate-ci/typos@master — a moving branch, not a tag. The PR body defers SHA-pinning to a future Renovate run, but a security-tooling bundle should not ship in a less-pinned state than the workflows it sits next to. Either SHA-pin in this PR (matching the existing # v2.19.0 SHA-comment style from 6353181), or open a follow-up that lands before this merges.

  2. link-check.yml peter-evans/create-issue-from-file step references ./lychee/out.md, but the lychee step never writes a file to that path. lycheeverse/lychee-action@v2 writes results to ${{ steps.lychee.outputs.report-file }} (or stdout). As written, the issue-creation step will fail with "no such file" on every link-check failure — silently, since the workflow is scheduled. Either set output: ./lychee/out.md on the lychee step (if supported in v2 — verify), or read from the action's report-file output.

Non-blocking but worth fixing before merge

  1. mutation.yml does uv sync --frozen --extra dev --extra archive then uv pip install mutmut. The pip install bypasses the lockfile, which is the lockfile-discipline equivalent of unpinning. Either add mutmut as a dev/optional dep in pyproject.toml and re-lock, or accept the deviation explicitly in the workflow comment.

  2. deadcode.yml runs deptry src with no continue-on-error, so any pre-existing undeclared/unused dep findings will block the next PR that touches pyproject.toml. Vulture has continue-on-error: true (advisory). Inconsistent — pick one posture and document it in the workflow.

  3. zizmor.yml uses astral-sh/setup-uv@v5 without with: enable-cache: true while the other uv-using workflows do. Minor, but worth aligning.

Observation, not a request

The branch-protection-required checks (pytest (3.12), pytest (3.13), secrets-scan, pattern-scan, history-scan) don't appear in this PR's check rollup at all — only the new workflows + Sourcery + CodeRabbit ran. That implies the existing required workflows have paths: filters that exclude .github/workflows/** + docs/** + *.toml. Worth confirming the merge-queue treatment is "required when run" rather than "required to be present" — otherwise this PR could merge with literally zero of the contract checks executed.

Will not merge as-is. Please address blockers 1 and 2, then re-flag for review.

@yoshi280

Copy link
Copy Markdown
Collaborator Author

[release:review:Toug:2026-04-30T22:19:35Z]

Static analysis for GitHub Actions workflow files. Catches common
misconfigurations (broad token scopes, script-injection sinks, unpinned
third-party actions) and uploads SARIF results to the Security tab.

Triggered on workflow file changes, push to main, and weekly cron.
Harden-Runner is in audit mode so the egress baseline can be reviewed
before promoting to block.
GitHub-native semantic code analysis. The python language pack covers
the src/ tree; the actions pack flags vulnerable workflow patterns
(complementary to zizmor's static lint).

security-extended + security-and-quality query suites enabled. Results
land in the Security tab. Free for public repos.
Crawls all .md and .rst files for broken links once a week (Mondays
14:00 UTC). On failure, opens an issue with the broken-link report
attached so it shows up in the issue list rather than a silent CI red.
crate-ci/typos catches typos in identifiers, comments, and docs without
flagging legitimate jargon. Config in .typos.toml excludes lockfiles,
telemetry, and test fixtures, and ignores hex-like identifiers (commit
SHAs in CHANGELOG entries, etc).
deptry detects undeclared/unused/transitive imports relative to
pyproject.toml — catches the 'imported but never declared' failure mode
common when prototypes graduate to library code.

vulture finds unreachable functions, classes, and imports. Runs at
min-confidence 80 with continue-on-error: it surfaces signal in logs
without blocking PRs on false positives.
Runs Sunday 08:00 UTC. mutmut applies small mutations to src/aelfrice
and re-runs the test suite — surviving mutants reveal tests that pass
without actually asserting the behavior.

Report is uploaded as a 30-day artifact rather than a blocking gate;
mutation testing on a 200+ test suite is too noisy and slow for PR-time
enforcement, but a weekly snapshot is the solo-dev substitute for a
second human reviewing test quality.
Hosted repo-activity dashboard at ossinsight.io. Zero install — links
out from the README to a public analytics view of contributors, PR
velocity, and dependency graph.
Lightweight Nygard-style Architecture Decision Records under docs/adr/.
Plain markdown, no published site, no tooling. ADR 0001 records the
decision to keep ADRs at all; 0002 captures the two-repo physical
separation rationale that was previously only in commit history and
CLAUDE.md fragments.
Eight commits adding solo-dev tooling: zizmor (workflow auditor), CodeQL
(python+actions SAST), lychee (weekly link-rot), typos (PR spell-check),
deptry+vulture (dep/dead-code hygiene), mutmut (weekly mutation tests),
OSSInsight badge, ADR directory with first two records.

Verification:
- new workflow files: 6 (zizmor, codeql, link-check, typos, deadcode, mutation)
- existing workflows: untouched
- atomic commits: yes (one tool per commit)
- secrets required: none (Codecov skipped per user)
- README badge: OSSInsight added; build/CI badges unchanged
- ADRs: 0001 (record-decisions), 0002 (two-repo-separation)

Blockers (require user decision before merge):
- [user] Verify CodeQL `actions` language pack is enabled for the repo
  (default-on for public repos created after 2024; check Settings →
  Code security)
- [user] First mutmut run will be long (~1-4h on full suite). Consider
  manual workflow_dispatch on a quiet day before relying on the cron
- [user] Most actions reference floating major tags (@v4, @v5). Renovate's
  pinDigests rule should rewrite these to SHAs on next run; if it doesn't,
  diagnose Renovate before merging more workflows

Open questions:
- Harden-Runner is in audit mode on new workflows only. Existing workflows
  (ci.yml, staging-gate.yml, publish.yml, etc.) were not modified — adding
  Harden-Runner there is a separate follow-up to keep this PR focused

Rollback:
- git revert 258abda..HEAD (or delete the branch before merge)
Author names (Mattern), acronyms (FPR, PN), code identifiers (gard_NN,
c_thr, ba SQL alias), accepted variants (unparseable), and intentional
test-fixture misspellings (lisence, fragmints in test_noise_config.py)
are not typos. Allowlist them so the typos workflow goes green on the
existing tree.
Declare aelfrice and benchmarks as first-party. Ignore DEP002 for
pytest/pytest-timeout/pyright/nltk/tiktoken/datasets/huggingface_hub
(declared but not imported by src/ — dev/test/bench-only; reorganize
into PEP 735 groups as a follow-up). Ignore DEP001 for benchmarks
(in-repo top-level package via pytest pythonpath shim, not a PyPI
dep). Ignore DEP003 for tomli (Py 3.10 fallback for stdlib tomllib).

Lets the deadcode workflow go green on the existing tree.
The bundle already shipped .typos.toml with baseline excludes and
aelfrice/aelf identifiers. Move the new extend-words allowlist into
that file and drop the duplicate _typos.toml. Single source of truth
for typos config.
@robotrocketscience
robotrocketscience merged commit 1531a8e into main Apr 30, 2026
16 of 17 checks passed
@robotrocketscience
robotrocketscience deleted the ci/devtools-bundle branch April 30, 2026 22:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants