From a47ff6b0806825966d2d23e4f4acd131d51d1b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ahlert?= Date: Mon, 4 May 2026 10:51:24 -0300 Subject: [PATCH] refactor(skills): migrate config/user.md references to .apache-steward-overrides/user.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The framework adopted a snapshot+overrides architecture in PR #38. Under that design, per-user configuration (PMC status, local clone paths, optional tool backends) lives in the adopter repo, not in the framework. The security skills, however, still referenced the legacy config/user.md path from the pre-snapshot architecture. Changes: - Update 4 security skills (sync, import, fix, cve-allocate) to read from .apache-steward-overrides/user.md instead of config/user.md. - Add Step 9b to setup-steward/adopt.md to scaffold a user.md template during first-time adoption. - Update docs and tool adapters that referenced config/user.md: onboarding, prerequisites, gmail, ponymail, fix-workflow template. The fallback-interactive behaviour is preserved: when the file is missing, skills ask the user and offer to save the answer back. Fixes the structural gap where the framework docs described a config/ layer that was never created in the snapshot-based architecture. Signed-off-by: André Ahlert --- .claude/skills/security-cve-allocate/SKILL.md | 2 +- .claude/skills/security-issue-fix/SKILL.md | 10 ++-- .claude/skills/security-issue-import/SKILL.md | 6 +- .claude/skills/security-issue-sync/SKILL.md | 10 ++-- .claude/skills/setup-steward/adopt.md | 57 +++++++++++++++++++ docs/prerequisites.md | 2 +- docs/security/new-members-onboarding.md | 20 +++---- projects/_template/fix-workflow.md | 2 +- tools/gmail/draft-backends.md | 4 +- tools/gmail/operations.md | 2 +- tools/gmail/tool.md | 2 +- tools/ponymail/tool.md | 2 +- 12 files changed, 87 insertions(+), 32 deletions(-) diff --git a/.claude/skills/security-cve-allocate/SKILL.md b/.claude/skills/security-cve-allocate/SKILL.md index 39652c4a..77b91d54 100644 --- a/.claude/skills/security-cve-allocate/SKILL.md +++ b/.claude/skills/security-cve-allocate/SKILL.md @@ -179,7 +179,7 @@ Before touching the tracker, verify: tell the user up front to install `uv` (one command: `curl -LsSf https://astral.sh/uv/install.sh | sh`). 3. **Resolve the user's PMC status.** First try to read it from - [`config/user.md`](../../../config/user.md) → `role_flags.pmc_member` + `.apache-steward-overrides/user.md` → `role_flags.pmc_member` (see [`config/README.md`](../../../config/README.md) for the config layer explainer). If the file exists and the flag is set, use that value and surface it in the Step 0 recap (*"loaded config for diff --git a/.claude/skills/security-issue-fix/SKILL.md b/.claude/skills/security-issue-fix/SKILL.md index b25ead4a..43d24247 100644 --- a/.claude/skills/security-issue-fix/SKILL.md +++ b/.claude/skills/security-issue-fix/SKILL.md @@ -148,10 +148,10 @@ tracker only to discover you cannot push the branch. directly — a fork is required. - **A clean local clone of ``** reachable from the agent's working directory. The path comes from the user's - [`config/user.md`](../../../config/user.md) → + `.apache-steward-overrides/user.md` → `environment.upstream_clone`; if the file or key is missing, the skill asks the user interactively and offers to save the - answer back into `config/user.md` so the next run is silent. The + answer back into `.apache-steward-overrides/user.md` so the next run is silent. The skill does **not** guess filesystem layouts — there is no hard-coded search path. The clone must: - have a remote pointing at your fork; @@ -313,14 +313,14 @@ change; it writes into a local clone of ``. Before touching any files: 1. Resolve the clone path from the user's - [`config/user.md`](../../../config/user.md) → + `.apache-steward-overrides/user.md` → `environment.upstream_clone` (see [`config/README.md`](../../../config/README.md) for the config layer explainer). If the file is missing, the key is unset, or the stored path does not resolve to a git repo with a remote pointing at `` or the user's fork, **ask the user for the path interactively** and offer to save their answer back - into `config/user.md` so the next run is silent. Do **not** + into `.apache-steward-overrides/user.md` so the next run is silent. Do **not** probe hard-coded paths like `~/code/airflow` — filesystem layouts vary per user and a wrong guess masks a misconfigured clone. @@ -328,7 +328,7 @@ touching any files: and which is the upstream ``. Per the rule in [`/AGENTS.md`](https://github.com//blob/main/AGENTS.md), push only to the user's fork, never to `` directly. - If the user's `config/user.md` has + If the user's `.apache-steward-overrides/user.md` has `environment.upstream_fork_remote` set, prefer that remote name; otherwise use the first non-`origin` remote that looks like a fork. If no fork remote is configured, **stop and ask the user diff --git a/.claude/skills/security-issue-import/SKILL.md b/.claude/skills/security-issue-import/SKILL.md index 1ff9f173..63bd4dfc 100644 --- a/.claude/skills/security-issue-import/SKILL.md +++ b/.claude/skills/security-issue-import/SKILL.md @@ -173,7 +173,7 @@ Before touching any candidate thread, verify: (401, 403, 404), stop and tell the user to log in with `gh auth login` or get added to ``. 3. **PonyMail MCP status** (opt-in; primary read path when - enabled) — read `config/user.md` → `tools.ponymail`. If + enabled) — read `.apache-steward-overrides/user.md` → `tools.ponymail`. If `enabled: true`, call `mcp__ponymail__auth_status()` once and record `ponymail_enabled` + `ponymail_authenticated` in the skill's observed-state bag. **When authenticated, downstream @@ -246,7 +246,7 @@ lags the inbox by minutes-to-hours for brand-new messages, which is exactly the window this skill most cares about. When PonyMail MCP is enabled and authenticated (Step 0) **and** -`security@.apache.org` is in `config/user.md` → +`security@.apache.org` is in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, run the archive as a **paired authoritative check** against the Gmail result set: @@ -550,7 +550,7 @@ in short: **Backend selection.** When PonyMail MCP is enabled and authenticated (Step 0) **and** `security@.apache.org` -is in `config/user.md` → `tools.ponymail.private_lists`, +is in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, **PonyMail MCP is the primary backend for this step**: ```text diff --git a/.claude/skills/security-issue-sync/SKILL.md b/.claude/skills/security-issue-sync/SKILL.md index e700eaf6..8364ce40 100644 --- a/.claude/skills/security-issue-sync/SKILL.md +++ b/.claude/skills/security-issue-sync/SKILL.md @@ -347,7 +347,7 @@ Before reading any tracker state, verify: ``. A 401/403/404 means the user needs `gh auth login` or collaborator access. 3. **PonyMail MCP status** (opt-in; primary read path when - enabled) — read `config/user.md` → `tools.ponymail`. If + enabled) — read `.apache-steward-overrides/user.md` → `tools.ponymail`. If `enabled: true`, call `mcp__ponymail__auth_status()` once. Three outcomes: - **Authenticated session** — record @@ -371,7 +371,7 @@ Before reading any tracker state, verify: user who set `enabled: true` in config but has not registered the MCP in Claude Code's `mcpServers` block gets the Gmail-only path without a noisy error. - When `config/user.md` sets `enabled: false` or omits the + When `.apache-steward-overrides/user.md` sets `enabled: false` or omits the `ponymail` block entirely, skip this sub-step; Gmail is the only read backend. See [`tools/ponymail/tool.md`](../../../tools/ponymail/tool.md) @@ -475,7 +475,7 @@ set is the strongest signal for what milestone the security issue should carry. **Backend selection.** When Step 0 recorded `ponymail_authenticated: true` **and** -`security@.apache.org` is in `config/user.md` → +`security@.apache.org` is in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, **PonyMail MCP is the primary backend for this step** — the archive is authoritative and reaches back further than any single user's Gmail window. Run the @@ -613,7 +613,7 @@ it for: historical lookups, cross-list fan-outs reliably find messages older than ~90 days. Gmail is the fallback when (a) PonyMail is not enabled / not authenticated, (b) a private list the query targets is not in -`config/user.md` → `tools.ponymail.private_lists`, or (c) the +`.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, or (c) the signal is *just-arrived inbound mail* where Gmail's inbox latency beats the archive's indexing delay. The per-issue budget is ≤ 2 archive searches (whichever backend) plus ≤ 3 Gmail inbox @@ -720,7 +720,7 @@ uses for reporter threads. That is the load-bearing signal path. **Backend selection.** When PonyMail MCP is enabled and authenticated (Step 0) **and** `security@.apache.org` is -in `config/user.md` → `tools.ponymail.private_lists`, **PonyMail +in `.apache-steward-overrides/user.md` → `tools.ponymail.private_lists`, **PonyMail MCP is the primary path** for reviewer-comment archive queries: ```text diff --git a/.claude/skills/setup-steward/adopt.md b/.claude/skills/setup-steward/adopt.md index b1680e55..2e3aa0cb 100644 --- a/.claude/skills/setup-steward/adopt.md +++ b/.claude/skills/setup-steward/adopt.md @@ -230,6 +230,63 @@ Framework changes go via PR to `apache/airflow-steward`. This directory is **committed** (overrides ship with the adopter repo). +## Step 9b — Scaffold `.apache-steward-overrides/user.md` (FRESH only) + +Create `/.apache-steward-overrides/user.md` with a +project-agnostic template. The security skills read this file at +run-time to resolve per-user preferences (PMC status, local clone +paths, optional tool backends). If the file is missing, the skills +fall back to interactive prompting and offer to save the answer +back into this file. + +```markdown +# Per-user configuration for apache-steward + +This file is committed in the adopter repo and holds preferences +that vary per developer (GitHub handle, local clone paths, optional +tool backends). It is **not** project-specific — those facts live in +`/project.md`. Fill in the fields that apply to your +setup; the skills skip any block that is missing or marked `TODO`. + +## `role_flags` + +- `pmc_member: TODO` — set to `true` if you are a PMC member of the + adopting project. Used by `security-cve-allocate` to decide whether + you can submit the CVE allocation form directly or need to relay + the request to a PMC member. + +## `environment` + +- `upstream_clone: TODO` — absolute path to your local clone of the + public `` repo. Used by `security-issue-fix` when it + writes changes and opens PRs. The skill validates that the clone + has a remote pointing at your fork before proceeding. +- `upstream_fork_remote: TODO` — name of the git remote that points + at your personal fork (e.g. `fork`, `your-github-handle`). If + omitted, the skill uses the first non-`origin` remote that looks + like a fork. Explicitly setting this avoids ambiguity when you + have multiple remotes. + +## `tools` + +### `ponymail` + +- `enabled: false` — set to `true` if you have registered the + PonyMail MCP in your Claude Code `mcpServers` block. When enabled + and authenticated, the security skills use PonyMail as the primary + read backend for mailing-list archive queries; Gmail remains the + fallback for just-arrived inbound mail and the only backend for + draft composition. +- `private_lists: []` — list of private mailing-list addresses that + PonyMail should query (e.g. `["security@.apache.org"]`). + Only used when `enabled: true`. +``` + +Show the file to the user and offer to fill in the `TODO` fields +interactively (one prompt per field, skipping any the user does not +yet know). After the interactive fill, write the file to disk and +git-add it. + ## Step 10 — Worktree-aware post-checkout hook (FRESH only) Install diff --git a/docs/prerequisites.md b/docs/prerequisites.md index a45ae1f3..76930ffa 100644 --- a/docs/prerequisites.md +++ b/docs/prerequisites.md @@ -131,7 +131,7 @@ checks and tests, pushes a branch to your fork, and opens a PR via `gh pr create --web`. You need: - a clean clone of `` reachable from the agent's working - directory — the path comes from `config/user.md → + directory — the path comes from `.apache-steward-overrides/user.md → environment.upstream_clone`, set interactively the first time you run the skill; - the adopting project's dev toolchain installed per its contributing diff --git a/docs/security/new-members-onboarding.md b/docs/security/new-members-onboarding.md index 007ece81..05ed5abc 100644 --- a/docs/security/new-members-onboarding.md +++ b/docs/security/new-members-onboarding.md @@ -119,13 +119,12 @@ week. A good starting routine: name — leaves the private channels. 6. **Set up your per-user config** if (and only if) you plan to run the agent skills. Copy - [`config/user.md.example`](config/user.md.example) to - `config/user.md` and fill in your GitHub handle, email, PMC status, - and (for remediation-developer work) the path to your local - `` clone. The full tutorial is in - [`config/README.md`](config/README.md) — it takes under five - minutes. You can skip this step on day one; skills fall back to - runtime prompts when `config/user.md` is missing. + `.apache-steward-overrides/user.md` (scaffolded automatically when + the project adopts steward) and fill in your GitHub handle, email, + PMC status, and (for remediation-developer work) the path to your + local `` clone. You can skip this step on day one; + skills fall back to runtime prompts when + `.apache-steward-overrides/user.md` is missing. You can start commenting on issues on day one. Just commenting, voting on validity, suggesting severity — those are valuable @@ -193,7 +192,7 @@ remediation-developer turn: pre-fix sync, reads the discussion on the tracker to build a fix plan, shows you the plan, and — only after you confirm — writes the change in your local `` clone (path from - `config/user.md → environment.upstream_clone`), runs the local + `.apache-steward-overrides/user.md → environment.upstream_clone`), runs the local checks and tests, and opens a public `gh pr create --web` PR from your fork. Every public surface (commit message, branch name, PR title, PR body, newsfragment) is scrubbed for CVE / the tracker @@ -230,9 +229,8 @@ shape the team are small enough to read in one sitting: - [`README.md`](../../README.md) — the end-to-end handling process. - [`/canned-responses.md`](/canned-responses.md) — reply templates. - [`AGENTS.md`](../../AGENTS.md) — agent-facing conventions and confidentiality rules. -- [`config/README.md`](config/README.md) — how the per-project and - per-user configuration layers work, with a tutorial for your own - `config/user.md`. +- `.apache-steward-overrides/user.md` — per-user configuration (PMC status, + local clone paths, optional tool backends) scaffolded during adoption. - [`/`](/) — project-specific content (roster, release trains, security model, scope labels, milestones, canned responses, fix-workflow specifics) — lives in the adopter's diff --git a/projects/_template/fix-workflow.md b/projects/_template/fix-workflow.md index 0a87bb7f..9a77f124 100644 --- a/projects/_template/fix-workflow.md +++ b/projects/_template/fix-workflow.md @@ -51,7 +51,7 @@ TODO: list the project's developer toolchain. Example shape: The `security-issue-fix` skill assumes a clean clone of `` reachable from the agent's working directory (path from -`config/user.md → environment.upstream_clone`), with a remote named +`.apache-steward-overrides/user.md → environment.upstream_clone`), with a remote named for the user's GitHub fork that `gh pr create` can push to. ## Backport labels diff --git a/tools/gmail/draft-backends.md b/tools/gmail/draft-backends.md index 92fffe35..5457528b 100644 --- a/tools/gmail/draft-backends.md +++ b/tools/gmail/draft-backends.md @@ -22,7 +22,7 @@ # Gmail drafting backends The skills create Gmail drafts via one of two backends, selected by the -user in [`config/user.md`](../../config/user.md) under +user in `.apache-steward-overrides/user.md` under `tools.gmail.draft_backend`: | Backend | Value | `threadId` attach? | Setup | @@ -70,7 +70,7 @@ on disk, the skills should always use them. Resolution: 1. **Probe for `oauth_curl` credentials** in this order: - `tools.gmail.oauth_credentials_path` from - [`config/user.md`](../../config/user.md) when set; + `.apache-steward-overrides/user.md` when set; - the `$GMAIL_OAUTH_CREDENTIALS` environment variable; - the default path `~/.config/apache-steward/gmail-oauth.json`. diff --git a/tools/gmail/operations.md b/tools/gmail/operations.md index 0d75e263..2252d1d5 100644 --- a/tools/gmail/operations.md +++ b/tools/gmail/operations.md @@ -99,7 +99,7 @@ only fetch bodies for the narrow set that actually warrants it ### Drafting backends Draft creation runs through one of two backends, selected by the user -in [`config/user.md`](../../config/user.md) under +in `.apache-steward-overrides/user.md` under `tools.gmail.draft_backend`. The full comparison and rationale live in [`draft-backends.md`](draft-backends.md); the call shape per backend is here. diff --git a/tools/gmail/tool.md b/tools/gmail/tool.md index d3ce70f9..10670498 100644 --- a/tools/gmail/tool.md +++ b/tools/gmail/tool.md @@ -55,7 +55,7 @@ cannot compose reporter replies. **Role when PonyMail MCP is opted into.** When a user sets `tools.ponymail.enabled: true` in their -[`config/user.md`](../../config/README.md) and authenticates the +`.apache-steward-overrides/user.md` and authenticates the MCP, PonyMail becomes the primary read backend for archive queries (reporter-thread lookups, reviewer-comment searches, `users@` / `dev@` archive scans, prior-rejection precedents). diff --git a/tools/ponymail/tool.md b/tools/ponymail/tool.md index d28ec4d5..1015476b 100644 --- a/tools/ponymail/tool.md +++ b/tools/ponymail/tool.md @@ -79,7 +79,7 @@ The two are **not** interchangeable today. Specifically: **Primary vs. fallback.** When a project declares both tools in its manifest **and** the user opts into PonyMail MCP in -`config/user.md`, **PonyMail MCP is the primary read backend** for +`.apache-steward-overrides/user.md`, **PonyMail MCP is the primary read backend** for archive queries (reporter-thread lookups, reviewer-comment searches, advisory-URL scans, `[RESULT][VOTE]` attribution, prior-rejection precedent searches). Gmail is the fallback —