---
phase: 05-publish-and-deploy
plan: 01
subsystem: infra
tags: [github-actions, ci-cd, pypi, oidc, trusted-publisher, python]

# Dependency graph
requires:
  - phase: 04-docs
    provides: pyproject.toml with package metadata and SDK source
provides:
  - GitHub Actions CI workflow (test matrix + version check on PRs)
  - GitHub Actions publish workflow (OIDC trusted publisher to PyPI on push to main)
  - pyproject.toml updated to drop EOL Python 3.9
affects:
  - 05-02 (docs deployment)
  - 05-03 (release process)

# Tech tracking
tech-stack:
  added:
    - "actions/checkout@v4"
    - "actions/setup-python@v5"
    - "maybe-hello-world/pyproject-check-version@v4"
    - "pypa/gh-action-pypi-publish@release/v1"
    - "actions/upload-artifact@v4"
    - "actions/download-artifact@v4"
  patterns:
    - "Two-job build+publish pattern with artifact passing between jobs"
    - "OIDC Trusted Publisher (id-token: write scoped to publish job only)"
    - "PR gate: test matrix (3.10-3.13) + mandatory version bump enforcement"

key-files:
  created:
    - ".github/workflows/ci.yml"
    - ".github/workflows/publish.yml"
  modified:
    - "pyproject.toml"

key-decisions:
  - "Drop Python 3.9 (EOL Oct 2025) — require >=3.10"
  - "OIDC id-token: write scoped to publish job only (not workflow-level) for security"
  - "version-check job fails if local version is not higher than PyPI — enforces version bumps on every PR"
  - "Two-job build+publish pattern: build job creates dist/, publish job downloads and uploads to PyPI"

patterns-established:
  - "Per-job OIDC permissions: permissions.id-token at job level, not workflow level"
  - "Artifact handoff: upload-artifact in build job, download-artifact in publish job"
  - "Version gate on PR: pyproject-check-version@v4 prevents merging without bumping"

# Metrics
duration: 1min
completed: 2026-02-27
---

# Phase 5 Plan 01: CI/CD Workflows Summary

**GitHub Actions CI (test matrix 3.10-3.13 + version gate) and PyPI publish via OIDC Trusted Publisher in a two-job build+publish pipeline**

## Performance

- **Duration:** 1 min
- **Started:** 2026-02-27T13:23:31Z
- **Completed:** 2026-02-27T13:24:40Z
- **Tasks:** 2
- **Files modified:** 3

## Accomplishments
- Updated pyproject.toml to require Python >=3.10, dropping EOL Python 3.9
- Created ci.yml: PR gate with test matrix across Python 3.10, 3.11, 3.12, 3.13 and a version-check job that prevents merging without a version bump
- Created publish.yml: two-job pipeline (build creates dist/, publish uploads to PyPI via OIDC) with id-token: write scoped to publish job only

## Task Commits

Each task was committed atomically:

1. **Task 1: Update pyproject.toml Python version and create CI workflow** - `ff4deac` (feat)
2. **Task 2: Create PyPI publish workflow** - `eeab31e` (feat)

**Plan metadata:** (see docs commit below)

## Files Created/Modified
- `pyproject.toml` - Changed requires-python from >=3.9 to >=3.10
- `.github/workflows/ci.yml` - PR gate: test matrix (3.10-3.13) + version bump enforcement
- `.github/workflows/publish.yml` - PyPI trusted publisher via OIDC, two-job build+publish pattern

## Decisions Made
- Drop Python 3.9 (EOL since October 2025) — requires-python bumped to >=3.10
- OIDC `id-token: write` permission placed on the `publish` job only (not workflow-level) — required for Trusted Publisher security model
- version-check job uses `maybe-hello-world/pyproject-check-version@v4` to enforce version bumps on every PR to main — prevents accidental merges without version increment
- Two-job build+publish pattern used so dist/ artifact is built once and published separately, enabling future signing steps between jobs

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered
None.

## User Setup Required
**External services require manual configuration.** The GitHub Actions workflows require:

1. **PyPI Trusted Publisher setup** — Go to https://pypi.org/manage/account/publishing/ and add a new Trusted Publisher:
   - Publisher: GitHub
   - Owner: [your-github-username]
   - Repository: meshulash_guard (or your repo name)
   - Workflow: publish.yml
   - Environment: pypi

2. **GitHub Environment** — In your GitHub repo Settings > Environments, create an environment named `pypi`.

3. **Verify:** After the first push to `main`, check the Actions tab — the publish job should succeed without requiring any stored secrets.

## Next Phase Readiness
- CI/CD pipeline complete and ready for use
- Next: Plan 05-02 (docs deployment to docs.meshulash.ai)
- Next: Plan 05-03 (release checklist / first PyPI publish)
- Workflows will trigger on first PR and first push to main respectively

---
*Phase: 05-publish-and-deploy*
*Completed: 2026-02-27*
