python-package/skills/security-supply-chain/SKILL.md
This skill should be used when the user is setting up trusted publishing, configuring OIDC for PyPI, enabling Sigstore attestations, writing a SECURITY.md, running pip-audit, scanning for vulnerabilities, configuring Dependabot or Renovate, setting up CodeQL, working with OpenSSF Scorecard, enabling 2FA on PyPI, defending against typosquatting, or hardening CI permissions. Covers PEP 740, SLSA framework, SPDX license compliance (PEP 639), and supply chain security best practices.
npx skillsauth add oborchers/fractional-cto security-supply-chainInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Supply chain attacks are the fastest-growing threat to open source. A single leaked PyPI API token can push a malicious release to millions of users. Trusted publishing eliminates long-lived tokens entirely. Sigstore attestations give users cryptographic proof of provenance. pip-audit catches known vulnerabilities before they ship. These are not optional hardening steps -- they are baseline requirements for any published package.
Trusted publishing is the single most important security improvement a package maintainer can make. It replaces long-lived API tokens with short-lived OIDC tokens that prove the publish request originated from a specific CI workflow.
| Aspect | API Tokens | Trusted Publishing | |--------|-----------|-------------------| | Lifetime | Long-lived (until revoked) | Seconds (per-job) | | Scope | Can upload any version | Tied to specific workflow + repo | | Storage | Must be stored as a secret | No secret to store | | Rotation | Manual, often neglected | Automatic (every run) | | Compromise impact | Attacker pushes malicious release | No credential to steal |
pypi.org/manage/project/YOUR-PACKAGE/settings/publishing/ -- add GitHub Actions as a trusted publisher with owner, repo, workflow filename, and environment namerelease with required reviewers and deployment branch restrictions (main or v* tags)permissions: id-token: write and environment: releaseFor new packages, use a "pending publisher" at pypi.org/manage/account/publishing/ to claim the name before the first release.
Delete all existing PyPI API tokens after migrating. There is no reason to keep them.
Enable with one flag in the publish action:
- uses: pypa/gh-action-pypi-publish@release/v1
with:
attestations: true
This generates Sigstore-based attestations proving who published the package, from which repository, and at which commit. Attestations are stored alongside each distribution file on PyPI and are verifiable by anyone:
python -m sigstore verify identity \
my_package-1.0.0-py3-none-any.whl \
--cert-identity "https://github.com/my-org/my-package/.github/workflows/publish.yml@refs/tags/v1.0.0" \
--cert-oidc-issuer "https://token.actions.githubusercontent.com"
Separate build and publish into distinct CI jobs. Pass artifacts via actions/upload-artifact, never rebuild at publish time.
SLSA Level 2 is achievable today for any package using GitHub Actions with trusted publishing:
| Level | What It Requires | What Python Packages Need |
|-------|-----------------|--------------------------|
| L1 | Provenance exists, build documented | Any CI-based build |
| L2 | Hosted build, signed provenance | GitHub Actions + trusted publishing + attestations |
| L3 | Hardened, isolated builds | slsa-framework/slsa-github-generator |
Target L2 as the minimum. L3 requires dedicated tooling but is achievable for high-value packages.
Run pip-audit --strict in every CI pipeline. It queries the OSV database covering NVD, GitHub Security Advisories, and other sources.
# In CI
- name: Audit dependencies
run: |
pip install pip-audit
pip-audit --strict --desc
Run on three triggers: every push to main, every pull request, and a weekly schedule (to catch newly disclosed CVEs). Generate an SBOM with pip-audit --format cyclonedx --output sbom.json for compliance records.
Every published package needs a SECURITY.md at the repository root. Include these sections:
# Security Policy
## Supported Versions
| Version | Supported |
|---------|--------------------|
| 2.x | Currently supported |
| 1.x | Security fixes only (until YYYY-MM-DD) |
| < 1.0 | No longer supported |
## Reporting a Vulnerability
**Do NOT report security vulnerabilities through public GitHub issues.**
### Preferred: GitHub Security Advisories
Go to the Security Advisories page and click "Report a vulnerability".
### Alternative: Email
Send details to [email protected].
## Response Timeline
| Stage | Target |
|-------|--------|
| Acknowledgment | Within 48 hours |
| Initial assessment | Within 1 week |
| Fix development | Within 30 days (critical/high) |
| Public disclosure | Coordinated, typically 90 days |
Enable GitHub Private Vulnerability Reporting under Settings > Security > Code security and analysis.
See the ci-cd skill for the full Dependabot configuration with uv ecosystem support and groups. Ensure both uv (or pip for non-uv projects) and github-actions ecosystems are configured on a weekly schedule.
Enforce allowed licenses in CI with pip-licenses:
pip-licenses \
--allow-only="MIT;BSD-2-Clause;BSD-3-Clause;Apache-2.0;ISC;PSF-2.0;Python-2.0" \
--fail-on="GPL-3.0-or-later;AGPL-3.0-or-later"
Use an SPDX expression string, not the legacy table format. See the pyproject-toml skill for the full PEP 639 configuration and examples. Enforce license compliance in CI with pip-licenses.
Set restrictive defaults at the workflow level, grant specific permissions per job:
permissions: read-all # Workflow-level default
jobs:
test:
permissions:
contents: read
publish:
permissions:
id-token: write # Only for trusted publishing
Pin GitHub Actions by full commit SHA for immutability. Version tags (e.g., @v4) are convenient and used in most CI configs (see ci-cd skill), but SHA pinning provides stronger supply chain guarantees since tags can be moved:
# Most secure (SHA pinning)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.7
# Acceptable (version tag pinning)
- uses: actions/checkout@v4
Never use pull_request_target with a checkout of the PR branch -- it grants write permissions and secret access to fork PRs.
Enable all of these under Settings > Code security and analysis:
main -- require PR reviews, status checks, no force pushRun the Scorecard action to get a 0-10 security score and a concrete improvement roadmap:
- uses: ossf/scorecard-action@v2
with:
results_file: results.sarif
publish_results: true
High-impact checks: Branch-Protection, Security-Policy, Dependency-Update-Tool, Signed-Releases, Token-Permissions, Vulnerabilities.
Add the badge to your README:
[](https://scorecard.dev/viewer/?uri=github.com/YOUR-ORG/YOUR-PACKAGE)
Enable 2FA on PyPI immediately. Prefer hardware security keys (YubiKey, Titan) over TOTP. Generate and securely store recovery codes. With trusted publishing, you rarely need to log in to PyPI directly, reducing credential exposure.
When reviewing code for security and supply chain practices:
attestations: true in publish action)pip-audit --strict runs on every PR and on a weekly scheduleSECURITY.md exists with reporting instructions and response timelinepermissions: read-all is set, with per-job overridespull_request_target with PR branch checkouttools
This skill should be used when the user invokes any /plan-* command from the planning-tools plugin (/plan-context, /plan-master, /plan-open-questions, /plan-verify, /plan-tick, /plan-progress, /plan-delete), asks how Claude Code's plan files work, asks where plans are stored, asks to author or audit a multi-phase master planning document, asks how to walk through a plan's Open Questions interactively, asks how to write progress entries, or mentions ~/.claude/plans/ or .claude/planning-tools.local.md. Provides the index of planning-tools commands, the master-plan workflow lifecycle, the v0.3.0+ list-shape mandate (phases and questions as headings + bulleted scope items, never tables), the v0.3.2+ plain-bullet shape (no `- [ ]` checkboxes — heading emoji is the sole tick signal), the progress-entry methodology, and the mechanics of Claude Code's plan-mode file storage.
testing
This skill should be used by the plan-verifier agent and the /plan-verify command to audit a drafted master plan against a fixed checklist. Covers universal-core completeness, the v0.3.0+ no-tables-for-phases-or-questions rule, trigger-based section-coverage gaps, phase actionability (heading + per-phase TL;DR + bulleted scope + exit criteria), the v0.3.1+ per-phase TL;DR requirement, the v0.3.2+ plain-bullet scope shape (legacy `- [ ]`/`- [x]` accepted silently), the v0.3.3+ context-block shape (plan-level `**TL;DR:**` + bulleted metadata, legacy `>` blockquote accepted silently), integer phase numbering enforcement, dependency traceability, citation resolution, callout/evidence convention compliance, Open Questions placement, and the one-PR-per-master-plan rule. Single-owner of the audit checklist.
tools
This skill should be used when authoring, reviewing, or modifying a multi-phase master planning document via the planning-tools plugin (especially the /plan-master and /plan-verify commands). Codifies the universal core sections, trigger-based optional sections, integer-only phase numbering, Open Questions placement, one-PR-per-plan rule, status conventions, evidence attribution, callouts, cross-reference formats, the v0.3.0 list-shape mandate (phases and questions are heading + bulleted list, never markdown tables), the v0.3.1 per-phase TL;DR requirement (1–3 sentence what/why summary under each phase heading for glance-ability), the v0.3.2 plain-bullet scope shape (`- <action>` items, no `- [ ]` checkboxes — the phase status emoji is the sole tick signal), and the v0.3.3 context-block shape (a plan-level `**TL;DR:**` + a bulleted metadata list instead of a `>` blockquote; legacy blockquote blocks accepted silently). Project-agnostic — no ticket-prefix or plan-type taxonomy.
testing
This skill should be used when the user is adjusting spacing, padding, margins, content density, section gaps, vertical rhythm, or separation between elements. Also applies when reviewing whether a design feels cramped or too sparse, choosing between borders and whitespace for separation, or defining a spacing system. Covers the 4px/8px spacing system, macro vs micro whitespace, content density spectrum, separation techniques (whitespace > background shifts > borders), and vertical rhythm.