mirror of
https://github.com/AgriciDaniel/claude-blog.git
synced 2026-09-19 03:32:21 +08:00
2020316123
Independent re-audit (6 Codex slices) of shipped v1.11.0 surfaced real issues the first pass missed. Remediated across 54 files: Security: SSRF DNS-rebinding revalidation (generate_hero, blog_preflight); symlink TOCTOU on chart/hero/preflight/image writers (O_NOFOLLOW atomic); path traversal in blog-notebooklm/blog-google/blog-audio wrapper run.py; preflight allowlist-before-safety bypass (Gate 5); unescaped untrusted text to XSS in discourse + schema JSON-LD; arbitrary file read/write in audio/indexing/gsc batch flows. Correctness: validate_image_setup args reassignment crash; chart AttributeError on malformed input; preflight accepting 999/100 scores. Currency (verified vs live Google docs): Indexing API scoped to JobPosting/livestream only (was told for generic blog posts in 6 files); gemini-3.1-flash-image stable + gemini-3.1-flash-tts-preview; nanobanana preview-shutdown warnings. Hygiene: SKILL.md trimmed 470->330 lines (under token budget); count / version / command-contract coherence across README/CLAUDE/docs/.github; stale install.ps1 SHA; 10 new SSRF/injection/symlink regression tests. 252 tests pass, prose lint + plugin validate green, no secret leaks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.4 KiB
6.4 KiB
Contributing to claude-blog
Thank you for your interest in contributing to claude-blog!
Getting Started
- Fork and clone the repository
- Install dev dependencies:
pip install -e ".[dev]" - Run tests:
python -m pytest tests/ -v - Validate plugin metadata:
claude plugin validate .
Development
Project Structure
claude-blog/
├── .claude-plugin/ # Plugin metadata
│ ├── plugin.json # Manifest
│ └── marketplace.json # Marketplace catalog entry
├── skills/
│ ├── blog/ # Main orchestrator + references + templates
│ ├── blog-write/ # User-facing sub-skill
│ ├── blog-chart/ # Internal-only sub-skill
│ ├── blog-rewrite/
│ └── ... # 31 sub-skill dirs: 30 user-facing + 1 internal
├── agents/ # 5 specialized agents
├── scripts/ # 14 root-level Python helper scripts
├── tests/ # pytest test suite (security guardrails + script tests)
├── docs/ # Documentation (installation, commands, architecture, templates, troubleshooting, MCP)
└── .github/workflows/ # CI pipeline
Making Changes
- SKILL.md frontmatter must include
nameanddescription. Optional valid fields:user-invokable,argument-hint,license,compatibility,metadata,disable-model-invocation. Do NOT addallowed-tools(not a valid Claude Code spec field; thetests/test_security_guardrails.pytest enforces). - Reference paths in sub-skills use
references/(relative to installed location) OR full repo-root paths likeskills/blog/references/X.mdfor cross-skill references. - Template paths in sub-skills use
templates/(relative to installed location). - Agent frontmatter must NOT include
Bashin thetoolslist (blast-radius reduction for prompt-injection surfaces; enforced by tests). - Run
python -m pytest tests/ -vbefore submitting. - Run
claude plugin validate .before submitting.
Code Style
Python (scripts/, skills/*/scripts/):
- Python 3.11+. Use
from __future__ import annotationsin new files for forward-compatible type hints. - Stdlib-only for new scripts unless a hard dependency is justified. Existing scripts use
argparse,json,pathlib,datetime,re,collections,sys. - CLI shape: docstring (with Usage block) + argparse +
--format json|markdownflag + return-code int. - File I/O: use
pathlib.Path, NEVER unrestricted user paths. Validate via the_validate_input_path/_validate_output_pathhelpers inscripts/discourse_research.py(refuses symlinks, enforces size cap, checks regular file). - Exception handling: catch specifically (
FileNotFoundError,json.JSONDecodeError,ValueError); avoid bareexcept:(test enforces). - Tests live in
tests/test_<module>.pymirroring the script name; follow thetest_cognitive_load.pyandtest_discourse_research.pypatterns (subprocess invocation; happy / empty / contract tests).
Prose (SKILL.md, references/, docs/, CHANGELOG.md, CONTRIBUTORS.md):
- No em dashes or en dashes (U+2014, U+2013, or ASCII
--). Use periods, commas, semicolons, colons, or parentheses. Em dashes are the strongest AI-content tell and the project deliberately avoids them. Exception: pedagogical use inside backticks (e.g. when documenting the character itself). - Inline citations as
[name](url)markdown links (LAW 5 ofskills/blog/references/synthesis-contract.md). - No invented titles for sources (LAW 2).
- No trailing "Sources" block when sources are already cited inline (LAW 1).
- Tables and bullet lists where structure helps; prose where prose helps.
Commit messages:
- Conventional commits style:
type(scope): subject. Types:feat,fix,docs,chore,refactor,test,security. - Examples used in the project:
fix(lint):,docs(security):,chore(release):,feat(blog-discourse):. - Subject line under 72 characters.
- Body explains WHY, not WHAT (the diff shows what).
Security expectations
- Read
SECURITY.mdfor the project's threat model and trust boundaries. - Treat any new untrusted-data path (file from user, network response, agent output, project-root file) as crossing a trust boundary. Fence content explicitly (see
agents/blog-researcher.mdfor the WebFetch pattern; seeskills/blog/SKILL.md"Untrusted-Data Contract" section for the project-root pattern). - Project-root file loading (BRAND.md / VOICE.md / DISCOURSE.md and any future additions): use
scripts/load_untrusted_root.pyvia Bash; do NOT hand-roll a fence in the orchestrator's own token output. The helper generates CSPRNG nonces, scans for instruction-shaped patterns, emits mtime provenance, and refuses symlinks viaO_NOFOLLOW. Adding a new project-root file means: (a) add its basename toALLOWED_BASENAMESinscripts/load_untrusted_root.py, (b) add behavioral tests intests/test_load_untrusted_root.py, (c) document the new T12 surface inSECURITY.md. Hand-rolled fences re-introduce the documentation-only state v1.8.3 closed. - Prose hygiene:
scripts/lint_prose.pyenforces CONTRIBUTING.md prose rules (no em-dashes / en-dashes / ASCII double-hyphen) on every PR via CI. Run locally withpython3 scripts/lint_prose.pybefore pushing. - Credentials, API keys, tokens: NEVER hardcoded. Use environment variables; store files at mode 0o600 with atomic write (see
skills/blog-google/scripts/google_auth.py_harden_permspattern). - New CLI scripts must enforce size caps (DoS guard) and refuse symlinks (CWE-59) on any path argument.
Pull Requests
- Create a feature branch from
main. - Make your changes with clear conventional-commit messages.
- Ensure all tests pass (
python -m pytest tests/). - Ensure plugin validates (
claude plugin validate .). - Update
CHANGELOG.mdwith an[Unreleased]entry describing the change. - Submit a PR using the template. Fill in: type of change, linked issue, test plan, docs checklist, and security checklist (if applicable).
Reporting Issues
- Bugs / feature requests: open an issue at https://github.com/AgriciDaniel/claude-blog/issues (templates in
.github/ISSUE_TEMPLATE/). - Questions and ideas: use GitHub Discussions.
- Security disclosures: see SECURITY.md for the private reporting channel; do NOT open public issues for vulnerabilities.