diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..0999b5ec --- /dev/null +++ b/.gitattributes @@ -0,0 +1,18 @@ +# Files excluded from the source release artefact. +# `git archive` (used by release-rc-cut / release-build.md to build +# apache-magpie--source.zip) honours `export-ignore`, so the +# paths below are kept out of the signed source .zip that the [VOTE] +# votes on. Keep this list to VCS/CI/editor metadata — never source. + +.gitattributes export-ignore +.gitignore export-ignore +.github/ export-ignore +.idea/ export-ignore +.agents/ export-ignore +.pre-commit-config.yaml export-ignore +.lychee.toml export-ignore +.lycheecache export-ignore +.markdownlint.json export-ignore +.typos.toml export-ignore +.zizmor.yml export-ignore +.apache-magpie.session-state.json export-ignore diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..cc24b781 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,58 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Changelog](#changelog) + - [0.1.0](#010) + - [Framework](#framework) + - [Skill families](#skill-families) + + + + + +# Changelog + +All notable changes to Apache Magpie are recorded here. This project +adheres to [Semantic Versioning](https://semver.org/). + +## 0.1.0 + +First Apache Magpie release. Apache Magpie is a reusable, governance- +agnostic framework of agentic skills for maintaining open-source +projects — usable by ASF and non-ASF projects alike. + +This initial release establishes the framework and its skill families: + +### Framework + +- Snapshot-based **adoption mechanism** (`magpie-setup`) so a project + can adopt, upgrade, verify, and unadopt the framework from a pinned + snapshot, with per-adopter and per-user configuration layers. +- **Agentic mode taxonomy** (Triage, Mentoring, Drafting, Pairing) and + the state-change-boundary discipline every skill is held to + (human-in-the-loop on every state change; the agent drafts, the human + acts). +- **Trusted skill sources** — fetch, pin, and symlink skills from + external trust-listed sources. + +### Skill families + +- **Security** — the security-issue lifecycle from intake through + triage, CVE allocation, fix, and disclosure. +- **Release management** — the release lifecycle: planning, RC cut, + verification, vote, promote, announce, archive, and audit, with both + the `svnpubsub` and **Apache Trusted Releases (ATR)** distribution + backends documented. +- **PR management** — triage, code review, quick-merge, and stats for a + maintainer's pull-request queue. +- **Issue management** — triage, deduplication, reproduction, staleness + sweeps, and backlog statistics. +- **Contributor & committer** — nomination briefs, activity sweeps, + readiness tracking, and post-vote onboarding. +- **Audit** — CI-runner, dependency, license-compliance, and + flaky-test audits. + +See [`README.md`](README.md) and [`MISSION.md`](MISSION.md) for the +full scope, and [`docs/`](docs/) for the per-family documentation. diff --git a/MISSION.md b/MISSION.md index 1b8e79b8..b61ae817 100644 --- a/MISSION.md +++ b/MISSION.md @@ -32,10 +32,10 @@ ## Mission Apache Magpie is responsible for the creation and maintenance of software -related to creation and maintenance of software related to agent-assisted -repository maintainership and development, including issue and pull-request -triage, contributor mentoring, agent-drafted remediation, developer-side -development-cycle skills, and narrowly-scoped fix-and-merge automation +related to agent-assisted repository maintainership and development, +including issue and pull-request triage, contributor mentoring, +agent-drafted remediation, developer-side development-cycle skills, and +narrowly-scoped fix-and-merge automation ## Abstract diff --git a/projects/magpie/pmc-roster.md b/projects/magpie/pmc-roster.md new file mode 100644 index 00000000..550baf77 --- /dev/null +++ b/projects/magpie/pmc-roster.md @@ -0,0 +1,96 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Apache Magpie: PMC roster](#apache-magpie-pmc-roster) + - [Roster](#roster) + - [Resolution](#resolution) + + + + + +# Apache Magpie: PMC roster + +The PMC roster `release-vote-tally` reads to classify each `[VOTE]` +reply as binding (PMC member) or non-binding (committer / community). +Template: [`projects/_template/pmc-roster.md`](../_template/pmc-roster.md). + +Authoritative source is the project's official committee roster +(`https://whimsy.apache.org/roster/committee/magpie`). This file +mirrors it so the tally skill can resolve a `From:` address without +hitting LDAP every run. Keep it in sync; membership changes land in +Whimsy first. The roster below reflects the founding PMC recorded in +[`MISSION.md`](../../MISSION.md). + +## Roster + +| Apache ID | Name | Primary email | Binding since | +|---|---|---|---| +| `potiuk` | Jarek Potiuk (Chair) | `potiuk@apache.org` | `[resolution]` | +| `pkarwasz` | Piotr Karwasz | `pkarwasz@apache.org` | `[resolution]` | +| `eladkal` | Elad Kalif | `eladkal@apache.org` | `[resolution]` | +| `zeroshade` | Matthew Topol | `zeroshade@apache.org` | `[resolution]` | +| `gopidesu` | Pavan Kumar Gopidesu | `gopidesu@apache.org` | `[resolution]` | +| `amoghdesai` | Amogh Desai | `amoghdesai@apache.org` | `[resolution]` | +| `akm` | Andrew Musselman | `akm@apache.org` | `[resolution]` | +| `jmclean` | Justin Mclean | `jmclean@apache.org` | `[resolution]` | +| `jbonofre` | Jean-Baptiste Onofré | `jbonofre@apache.org` | `[resolution]` | +| `paulk` | Paul King | `paulk@apache.org` | `[resolution]` | +| `rusackas` | Evan Rusackas | `rusackas@apache.org` | `[resolution]` | +| `russellspitzer` | Russell Spitzer | `russellspitzer@apache.org` | `[resolution]` | +| `iemejia` | Ismael Mejia | `iemejia@apache.org` | `[resolution]` | +| `tison` | Zili Chen (tison) | `tison@apache.org` | `[resolution]` | +| `jamesfredley` | James Fredley | `jamesfredley@apache.org` | `[resolution]` | +| `kirs` | Calvin Kirs | `kirs@apache.org` | `[resolution]` | +| `rbowen` | Rich Bowen | `rbowen@apache.org` | `[resolution]` | +| `mdrob` | Mike Drob | `mdrob@apache.org` | `[resolution]` | +| `clr` | Craig L Russell | `clr@apache.org` | `[resolution]` | +| `csutherl` | Coty Sutherland | `csutherl@apache.org` | `[resolution]` | +| `remm` | Rémy Maucherat | `remm@apache.org` | `[resolution]` | +| `rzo1` | Richard Zowalla | `rzo1@apache.org` | `[resolution]` | + +**A `+1` from a PMC member is binding; from anyone not on this roster, +non-binding.** + +A `[VOTE]` reply counts as binding when: + +1. The `From:` address matches a row's `Primary email` exactly, **or** +2. The `From:` address contains `@apache.org` and the local part + matches a row's `Apache ID` exactly. + +Rule (2) is the fallback because PMC members occasionally vote from +`@apache.org` rather than the `Primary email` recorded here. + +> [!IMPORTANT] +> `Primary email` is set to each member's `@apache.org` address, so +> rules (1) and (2) both resolve an `@apache.org` vote. **A member who +> intends to vote from a personal Gmail or corporate address MUST have +> that address added to their `Primary email` here before the 0.1.0 +> `[VOTE]`** — otherwise neither rule matches and their `+1` tallies +> non-binding. `Binding since` is `[resolution]` for the founding +> roster; replace with the establishment-resolution date once +> confirmed (informational only; not used for resolution). + +## Resolution + +`release-vote-tally`'s resolution algorithm: + +1. Normalise the `From:` header to `local@domain` form. +2. Try exact match against `Primary email` (case-insensitive). +3. If `domain == apache.org`, try the local part against the + `Apache ID` column. +4. If neither hits, the vote is classified non-binding, flagged + `BINDING-CANDIDATE-UNRESOLVED`, and surfaced for RM review; the + skill refuses to count it until the RM updates this roster or + confirms the vote is non-binding. + +The roster is the source of truth for the tally skill. The skill never +infers binding status from message content (a sign-off that says "PMC +member" does not promote a non-roster voter to binding). + +> [!NOTE] +> Reconcile against the Whimsy roster before relying on this for a +> binding tally. Membership changes (additions, emeritus) land in +> Whimsy first. diff --git a/projects/magpie/release-build.md b/projects/magpie/release-build.md new file mode 100644 index 00000000..abe706a8 --- /dev/null +++ b/projects/magpie/release-build.md @@ -0,0 +1,66 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Apache Magpie: release build configuration](#apache-magpie-release-build-configuration) + - [Build invocation](#build-invocation) + - [Expected artefact list](#expected-artefact-list) + - [Digest set](#digest-set) + - [Binary-exclude list](#binary-exclude-list) + + + + + +# Apache Magpie: release build configuration + +Build invocation, expected artefact set, and digest selection the +`release-rc-cut` and `release-verify-rc` skills read for a Magpie +release. Template: [`projects/_template/release-build.md`](../_template/release-build.md). + +Magpie is a source-first project (skills, docs, and Python tooling). +**The source package is the release** per +[release-policy § what is a release](https://www.apache.org/legal/release-policy.html#release-definition). +Magpie ships **no convenience binaries** — the signed source artefact is +the only release artefact. + +## Build invocation + +The canonical source artefact is a deterministic `git archive` of the +tagged tree — no VCS metadata, no build output: + +```bash +# From the release tag -rcN: +git archive --format=zip \ + --prefix="apache-magpie-/" \ + -o "apache-magpie--source.zip" \ + "-rcN" +``` + +Files that must not ship in the source release (CI config, editor +metadata) are marked `export-ignore` in the root +[`.gitattributes`](../../.gitattributes), so `git archive` drops them. +[Apache RAT](https://creadur.apache.org/rat/) (run by +`release-verify-rc`) is the authoritative check on artefact contents; +extend the `export-ignore` set if RAT flags anything on the first RC. + +## Expected artefact list + +- `apache-magpie--source.zip` — canonical source artefact + (**required**, signed, checksummed). This is what the `[VOTE]` votes + on, and the only artefact Magpie ships. No convenience binaries. + +## Digest set + +- `sha512` — **required** (ASF baseline). + +`md5` and `sha1` are prohibited for new ASF releases per +[release-distribution § sigs-and-sums](https://infra.apache.org/release-distribution.html#sigs-and-sums) +and are never emitted. + +## Binary-exclude list + +The source artefact must contain no compiled or opaque binary content. +Conservative default denylist for `release-verify-rc`: +`.class`, `.jar`, `.so`, `.dylib`, `.dll`, `.exe`, `.pyc`. diff --git a/projects/magpie/release-management-config.md b/projects/magpie/release-management-config.md new file mode 100644 index 00000000..d2013856 --- /dev/null +++ b/projects/magpie/release-management-config.md @@ -0,0 +1,165 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Apache Magpie: release-management configuration](#apache-magpie-release-management-configuration) + - [Identifiers](#identifiers) + - [Backends](#backends) + - [Distribution URLs](#distribution-urls) + - [Signing](#signing) + - [Vote](#vote) + - [Announce](#announce) + - [Archive](#archive) + - [Audit log](#audit-log) + - [Category-X dependency denylist](#category-x-dependency-denylist) + + + + + +# Apache Magpie: release-management configuration + +Magpie's **own** release-management config (Magpie self-adopts the +framework — see [`.apache-magpie.lock`](../../.apache-magpie.lock)). +This is the live config the `release-*` skills read for a Magpie +release, not a scaffold. The adopter template lives at +[`projects/_template/release-management-config.md`](../_template/release-management-config.md); +this file is that template filled with Magpie's values. + +Magpie is an **ASF Top-Level Project** (established by Board +resolution — [`MISSION.md`](../../MISSION.md)), so it is pinned to the +mandatory ASF approval + announce mechanisms (`dev-list-vote`, +`announce-list`). + +> [!IMPORTANT] +> **Distribution backend = `svnpubsub`** (the ASF-ratified default), +> per the [`svnpubsub` runbook](../../docs/release-management/svn-release-runbook.md). +> **Apache Trusted Releases (ATR) is the intended direction** and is +> fully documented in the [ATR release runbook](../../docs/release-management/atr-release-runbook.md), +> but ATR is in **alpha** and its adoption is **pending a PMC +> ratification vote on `dev@`**. Until that vote passes, +> `release_dist_backend` stays `svnpubsub`. After ratification, switch +> the value below to `atr` (and see `atr_platform_url`); no other change +> to this file is needed, since the approval and announce mechanisms are +> backend-independent. + +## Identifiers + +| Key | Value | +|---|---| +| `project_dist_name` | `magpie` | +| `product_name` | `Apache Magpie` | +| `upstream` | `apache/magpie` | +| `release_planning_issue_template` | *(none — uses the `release-prepare` default template)* | +| `release_branch_base` | `main` | +| `version_manifest_files` | `pyproject.toml` | + +## Backends + +| Key | Value | Allowed values | +|---|---|---| +| `release_dist_backend` | `svnpubsub` | `svnpubsub`, `atr`, `github-releases`, `s3`, `self-hosted` | +| `release_approval_mechanism` | `dev-list-vote` | `dev-list-vote`, `github-discussion`, `pr-approval`, `maintainer-roster` | +| `release_announce_backend` | `announce-list` | `announce-list`, `github-release-notes`, `site-post`, `discord-channel` | + +As an ASF TLP, Magpie is pinned to `dev-list-vote` (mandatory per +[release-policy § release approval](https://www.apache.org/legal/release-policy.html#release-approval)) +and `announce-list` (mandatory per +[release-policy § announcements](https://www.apache.org/legal/release-policy.html#release-announcements)). +`release_dist_backend = svnpubsub` stages the RC under `dist/dev/` and +promotes to `dist/release/` on `dist.apache.org`; see the +[`svnpubsub` runbook](../../docs/release-management/svn-release-runbook.md). +Setting it to `atr` (after PMC ratification) instead drives compose / +check / vote / finish through the ATR platform; see the +[ATR release runbook](../../docs/release-management/atr-release-runbook.md). + +## Distribution URLs + +| Key | Value | +|---|---| +| `release_dist_url_template` | `https://dist.apache.org/repos/dist//magpie//` | +| `archive_url_template` | `https://archive.apache.org/dist/magpie/` | +| `atr_platform_url` | `https://release-test.apache.org/` *(only used once `release_dist_backend = atr`; alpha host, production will be `release.apache.org`)* | + +On the `svnpubsub` default, `` resolves to `dev` while the RC +is staged for the vote and `release` after promotion. On the `atr` +backend (post-ratification) the RC lives in ATR's draft/candidate area +during Compose+Vote and **Finish** publishes to `dist/release/magpie/`. + +## Signing + +| Key | Value | +|---|---| +| `keys_file_url` | `https://dist.apache.org/repos/dist/release/magpie/KEYS` | +| `keyserver` | `keys.openpgp.org` | +| `rm_key_fingerprint` | *(per-RM; lives in the RM's `user.md` under `release_manager.gpg_fingerprint`)* | + +The RM signs each artefact and the public key must be in `KEYS` (and, +once `release_dist_backend = atr`, also registered in the ATR platform, +which validates candidate signatures during Compose — see the ATR +runbook, Step B). The agent never holds the private key half. + +## Vote + +| Key | Value | +|---|---| +| `vote_dev_list` | `dev@magpie.apache.org` | +| `mail_archive` | `ponymail` | +| `mail_archive_url_template` | `https://lists.apache.org/list.html?dev@magpie.apache.org` | +| `vote_window_hours` | `72` | +| `vote_pass_rule_overrides` | *(none — ASF baseline: ≥3 binding +1, more +1 than -1)* | +| `vote_subject_template` | `[VOTE] Release Apache Magpie from -rcN` | +| `result_subject_template` | `[RESULT] [VOTE] Release Apache Magpie from -rcN` | +| `release_approver_roster_path` | `projects/magpie/pmc-roster.md` | + +`vote_window_hours` is a floor per +[release-policy § release approval](https://www.apache.org/legal/release-policy.html#release-approval). +The ≥72h window and the binding-vote rule are backend-independent; on +the `atr` backend the platform sends the `[VOTE]` and tabulates, but the +window and rule are unchanged. + +## Announce + +| Key | Value | +|---|---| +| `announce_list` | `announce@apache.org` | +| `announce_cc_lists` | `dev@magpie.apache.org` | +| `announce_subject_template` | `[ANNOUNCE] Apache Magpie released` | +| `site_repo` | `apache/magpie-site` *(TODO: confirm site repo name once the site is stood up)* | +| `site_pr_files` | *(TODO: set once the site structure exists)* | + +`announce@apache.org` is mandatory for the TLP announcement per +[release-policy § announcements](https://www.apache.org/legal/release-policy.html#release-announcements). + +## Archive + +| Key | Value | +|---|---| +| `archive_retention_rule` | `latest_of_each_supported_line` | + +Standard default per +[release-distribution](https://infra.apache.org/release-distribution.html): +only the latest version of each supported line stays on +`dist/release/magpie/`; superseded versions move to +`archive.apache.org`. + +## Audit log + +| Key | Value | +|---|---| +| `audit_log_path` | `audit/releases/` | + +`release-audit-report` appends one markdown record per release at +`audit/releases/.md`, proposed as a PR — never committed +directly. + +## Category-X dependency denylist + +| Key | Value | +|---|---| +| `category_x_dependencies` | *(empty — no known Category-X dependencies)* | + +The [ASF Category-X list](https://www.apache.org/legal/resolved.html#category-x) +is the fallback; this per-project list is the source of truth for +denial and is the PMC's responsibility to maintain. diff --git a/projects/magpie/release-trains.md b/projects/magpie/release-trains.md new file mode 100644 index 00000000..e0a6bcd7 --- /dev/null +++ b/projects/magpie/release-trains.md @@ -0,0 +1,48 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Apache Magpie: release trains](#apache-magpie-release-trains) + - [Trains](#trains) + - [Releases](#releases) + - [Release Manager roster](#release-manager-roster) + + + + + +# Apache Magpie: release trains + +Release-train identity and the Release Manager roster the release +skills (and the security family) read. Template: +[`projects/_template/release-trains.md`](../_template/release-trains.md). + +## Trains + +Magpie is pre-1.0 and runs a **single active train** off `main`. There +is no maintenance/backport line yet; that convention is added here when +the first `X.Y` line needs one. + +| Train | Branch | Status | Supported | +|---|---|---|---| +| `0.x` | `main` | active | latest `0.x` release only | + +## Releases + +| Version | Train | Release Manager | Notes | +|---|---|---|---| +| `0.1.0` | `0.x` | Jarek Potiuk (`potiuk`) | First Apache Magpie release. | + +## Release Manager roster + +Any PMC member may serve as Release Manager. The RM for a given release +is recorded in the *Releases* table above. Jarek Potiuk (`potiuk`), +PMC Chair, is the RM for the first release; RM assignment for +subsequent releases rotates per PMC agreement. + +The RM's signing-key fingerprint is **not** stored here — it lives in +the RM's personal `user.md` (`release_manager.gpg_fingerprint`), and +the public half must appear in the project +[`KEYS`](https://dist.apache.org/repos/dist/release/magpie/KEYS) file +and be registered in the ATR platform before the RC is cut. diff --git a/pyproject.toml b/pyproject.toml index 6687cda3..73a9a74a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,8 +32,8 @@ # Package name matches the project's canonical name. Not published to # PyPI — this name only frames the framework root as a uv-managed project. name = "apache-magpie" -version = "0.0.0" -description = "Reusable framework for handling security vulnerabilities in Apache projects." +version = "0.1.0" +description = "Reusable, governance-agnostic framework of agentic skills for maintaining open-source projects." requires-python = ">=3.11" [dependency-groups] diff --git a/uv.lock b/uv.lock index c99e4b6c..3f8d29be 100644 --- a/uv.lock +++ b/uv.lock @@ -86,7 +86,7 @@ dev = [ [[package]] name = "apache-magpie" -version = "0.0.0" +version = "0.1.0" source = { virtual = "." } [package.dev-dependencies]