Skip to content
Merged
4 changes: 2 additions & 2 deletions plugins/magpie-setup/skills/setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ when_to_use: >-
to the `welcome-guide` skill.
argument-hint: "[install|config|adopt|unadopt|upgrade|worktree-init|verify|reconcile|override skill-name|delegate [skill-name]|welcome|uninstall]"
capability: capability:platform
surface_hash: sha256:2557a934f9ea5576
surface_hash: sha256:cfae279d2c143532
license: Apache-2.0
measured_tokens: 5307
measured_tokens: 5306
---

<!-- SPDX-License-Identifier: Apache-2.0
Expand Down
30 changes: 28 additions & 2 deletions plugins/magpie-setup/skills/setup/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ When a vetted-ops policy exists, show the `[tracker]` table it needs —
`platform`, and `root` or the `jira_*` target (the backend's code comes from the tool installed beside vetted-ops, never from the policy)
([vetted-ops → Tracker backends](../../../../tools/vetted-ops/README.md#tracker-backends)) —
and write it only on the user's confirmation; the policy is a security control, not configuration this step may change unasked.
Grant the security callers `issue-create`, `issue-search`, `issue-list-label`, `issue-reopen`, `issue-body`, `issue-attach`, `tracker-doctor`, `tracker-pending` and `tracker-publish` in the same diff.
For **every configured security caller** (not only the three import callers), inspect the tracker operations its workflow actually uses through the [security-tracker command mapping](../../../../tools/security-tracker/contract.md#from-skill-commands-to-vetted-operations). Use the canonical [vetted-ops `[callers]` example](../../../../tools/vetted-ops/README.md#configuration) for its existing base grants, then propose the missing backend-specific operations for that caller only. Include applicable `tracker-doctor`, `issue-view`, `issue-comments`, `issue-create`, `issue-search`, `issue-list-label`, `issue-reopen`, `issue-body`, `issue-attach`, and, for local-files writes, `tracker-pending` and `tracker-publish`. This is an operation checklist, not a blanket permission grant. Show the exact per-caller diff and require confirmation; preserve existing operations and unrelated callers.

### Personal tool configs, for a project that has not adopted Magpie

Expand All @@ -344,10 +344,36 @@ and the sandbox profile denies the agent's writes to it (`Edit(//**/.git/**/apac
So the user saves it themselves, from the draft; never route around that deny to write it.
The CVE JSON config is ordinary configuration: write it on the user's yes.

## Import caller grants — independent of tracker selection

When any security issue-import workflow is configured, check its caller grants
even when `tracker.platform` is already configured. Do not make this check
conditional on [Step 3a](#step-3a--security-tracker-backend) running.

For an existing vetted-ops policy, read its `[callers]` table and derive the
applicable required operations from the canonical
[vetted-ops README configuration example](../../../../tools/vetted-ops/README.md#configuration).
Select the configured tracker backend and each distinct import caller.
Do not maintain another fixed caller-to-operation list here.

Show each missing caller or operation as a proposed policy diff. Preserve
existing permissions and unrelated callers; do not duplicate TOML keys.
Never add unrelated permissions. If the policy is missing, do not create it
implicitly. If it cannot be inspected, report the check as incomplete.

The vetted-ops policy is a security control: show the draft and let the
user save it after explicit confirmation, as described under
[Personal tool configs](#personal-tool-configs-for-a-project-that-has-not-adopted-magpie).
Do not bypass sandbox write restrictions.

A declined, unapplied, or unchecked import-grant proposal remains unresolved
and must not produce a clean reconciliation stamp for the affected skill.

## Step 3b — Record what this run reconciled

For every skill in scope (Step 1) whose `requires_config:` set now fully
resolves, record that fact, keyed by that skill's frontmatter `name:`
resolves **and whose applicable import caller grants have been verified**,
record that fact, keyed by that skill's frontmatter `name:`
(e.g. `code-review`). **Everything this step writes
stays inside the personal layer's `reconciled.json` — never the
committed lock, adopted project or not.** That is the personal layer
Expand Down
53 changes: 46 additions & 7 deletions plugins/magpie-setup/skills/setup/reconcile.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,29 @@ baseline required.
name>` requires `<file>`, which is not configured"* — propose
`/magpie-setup:setup config <skill>` for it.

3a. **Import caller policy grants.** When an existing vetted-ops policy
Comment thread
KatalKavya96 marked this conversation as resolved.
Resolved
is present and a security issue-import skill is in scope (step 1),
read its `[callers]` table. Compare the applicable caller against
the minimum permissions used by the skill:

Derive required operations from the canonical [vetted-ops README `[callers]` example](../../../../tools/vetted-ops/README.md#configuration), including backend-specific operations where applicable. Do not use a second hard-coded mapping.

A missing caller or missing required operation is a finding. Name the
caller, the missing operations, and the existing policy path. Propose
adding only those grants; do not grant `body-field-set`, which these
import workflows do not use. When a caller already exists, merge
missing operations into its existing TOML array rather than creating
a duplicate key. Preserve comments, unrelated callers and existing
permissions.

This is a security-control change, not an automatic repair. Show the
exact proposed diff and obtain item-by-item confirmation before
writing anything. A declined change leaves the policy unchanged and
the finding unresolved; do not report or stamp that configuration
as clean. If the policy does not exist, mark this check not applicable:
do not create a vetted-ops policy during reconciliation. If the
policy cannot be read or parsed, report it as unchecked, not clean.

4. **Sandboxed sessions cover what they can reach.** Resolving a
skill's anchors (check 2) needs that skill's `SKILL.md` **and its
sibling detail files**. On a pinned-snapshot install they sit inside
Expand Down Expand Up @@ -182,8 +205,8 @@ baseline required.

## Step 1 — Present the findings

List every finding from checks 2–3 as a numbered proposal, one item per
override or `requires_config` gap:
List every finding from checks 2–3a as a numbered proposal, one item per
override, `requires_config` gap, or missing import caller policy grant:

```text
1. .apache-magpie-overrides/issue-triage.md anchors to
Expand All @@ -195,8 +218,8 @@ override or `requires_config` gap:
→ /magpie-setup:setup config pr-management-code-review
```

No findings → say so plainly (*"every configured skill's anchors and
`requires_config` entries resolve"*), name any `unchecked` skills from
No findings → say so plainly (*"every configured skill's anchors,
`requires_config` entries and applicable vetted-ops caller grants resolve"*), name any `unchecked` skills from
check 4, and go straight to Step 2 with nothing to confirm — writing
the stamp needs no confirmation when nothing is changing.

Expand All @@ -209,6 +232,15 @@ maintainer's judgement call, not pattern-matching. A `requires_config`
gap can be closed mechanically by chaining into
`/magpie-setup:setup config <skill>`; offer it per item.

For an import caller policy finding (check 3a), show the minimum-grant
Comment thread
KatalKavya96 marked this conversation as resolved.
Resolved
TOML diff before asking. After confirmation, hand off to setup config
or let the user save the drafted policy; do not directly write the
security-control file from reconcile. A refusal does
not authorize a policy edit or a clean reconciliation stamp for that
unresolved configuration. Do not treat resolved `requires_config` files
alone as proof of a clean skill when its required caller grants are missing.
Preserve existing policy content not covered by the confirmed change.

Both `acknowledged` writes below fire **on decline**, not on show — unlike
the pre-flight block's own per-skill check
([`tools/dev/preflight-block.md`](../../../../tools/dev/preflight-block.md)
Expand All @@ -219,9 +251,16 @@ operator abandons mid-flow deliberately leaves nothing recorded, so the
proposal correctly returns on the next run instead of being silently
suppressed by a write that never happened.

- **Confirmed and applied** — the skill's configuration now resolves
cleanly. Its entry in the stamp's `skills:` map is written (or
refreshed) with its **current** `surface_hash`.
- **Confirmed and applied** — verify the resulting configuration
before writing the skill's clean stamp. For import caller policy
findings, re-read and parse the saved vetted-ops policy and confirm
that every required operation for the selected backend is present.
User confirmation of a draft alone is not proof of application.
If the policy is unchanged, missing a grant, or cannot be verified,
leave the finding unresolved and do not stamp that skill clean.
Only after all applicable checks pass may its entry in the stamp's
`skills:` map be written (or refreshed) with its **current**
`surface_hash`.
- **Declined** — nothing about the project changes. Write
`acknowledged.skills["<skill name>"]: <current surface_hash>` to the
local file so the per-skill pre-flight does not re-propose the exact
Expand Down
30 changes: 30 additions & 0 deletions plugins/magpie-vetted-ops/tools/vetted-ops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,36 @@ board_status_field_id = "PVTSSF_…" # its Status field id
"security-issue-import" = ["issue-list-with-bodies", "rollup-append"]
"security-issue-import-from-md" = ["rollup-append"]
"security-issue-import-from-pr" = ["pr-view-with-body", "rollup-append"]

# Non-GitHub tracker additions, per import caller.
# Add these to the corresponding existing caller array; preserve base grants.
#
# security-issue-import:
# jira: tracker-doctor, issue-search, issue-list, issue-list-label,
# issue-view, issue-comments, issue-comment, issue-create,
# issue-body, issue-attach
# local-files: same as jira, plus tracker-pending, tracker-publish
#
# security-issue-import-from-md:
# jira: tracker-doctor, issue-search, issue-view, issue-create,
# issue-body, issue-attach
# local-files: same as jira, plus tracker-pending, tracker-publish
#
# security-issue-import-from-pr:
# jira: tracker-doctor, issue-search, issue-view, issue-create,
# issue-set-milestone, issue-body, issue-attach
# local-files: same as jira, plus tracker-pending, tracker-publish
#
# These are conditional additions, not universal grants.
# issue-list-with-bodies works only with GitHub. The email importer must
# stop on Jira/local-files when this deduplication step is unsupported;
# never bypass the refusal or assume that unmatched reports are new.
#
# Other security callers (sync, fix, CVE allocation, deduplication,
# triage and invalidation) also require their own backend grants.
# Setup derives those from each workflow and the security-tracker contract,
# preserving existing grants and requesting explicit confirmation.
# Do not duplicate TOML keys or grant every operation to every caller.
"security-issue-invalidate" = ["rollup-append", "rollup-amend-latest"]
"security-issue-triage" = ["issue-view", "issue-comments",
"osv-get-vuln", "osv-query-package"]
Expand Down
2 changes: 1 addition & 1 deletion tools/skill-evals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Behavioral eval harness for Apache Magpie skills. Each eval suite tests a skill

Suites are currently implemented for:

- **setup** — 152 cases across 33 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser, adopt-isolation-warning, step-vetted-ops-no-policy, step-unknown-subaction)
- **setup** — 157 cases across 34 steps (step-verify-drift, step-overrides-surface, step-override-bypass, step-m3-baseline-pick, step-m4-install-gates, step-m5-no-repo-offer, step-m5-companion-offer, step-upgrade-companion-offer, step-adopt-settings-merge, verify-default-set, uninstall-default-set, lock-marketplace-parse, adopt-write-floor, setup-prefill-from-floor, preflight-floor, upgrade-adoption-split, verify-floor, adopt-review-process, adopt-security-list, step-reconcile, step-reconcile-confirmation, step-verify, step-config-stamp, step-config-adversarial, step-config-mail, step-adopt-stamp, step-upgrade-stamp, step-delegate-propose, config-vcs-backend, config-local-custom-parser, adopt-isolation-warning, step-vetted-ops-no-policy, step-unknown-subaction)
- **setup-isolated-setup-install** — 28 cases across 6 steps (runtime-routing, step-snapshot-drift, step-scope-confirm, step-hardware-key, step-roborev-exclusion, step-hook-manager-shim)
- **setup-privacy-llm** — 6 cases across 2 steps (step-1-resolve, step-4-gate)
- **setup-shared-config-sync** — 12 cases across 2 steps (step-3-decide-action, step-5-draft-commit)
Expand Down
16 changes: 14 additions & 2 deletions tools/skill-evals/evals/setup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Behavioral evals for the `setup` skill.

## Suites (152 cases total)
## Suites (157 cases total)

| Suite | Step | Cases | What it covers |
|---|---|---|---|
Expand All @@ -29,7 +29,8 @@ Behavioral evals for the `setup` skill.
| welcome-first-run | SKILL.md § First — the welcome guide | 3 | the `setup` skill's own hard-coded welcome check (the setup family runs no shared pre-flight): first Magpie run (show the general guide), general already seen (show the setup guide), both hidden (silent, and no setup finding sneaks in because only the welcome is checked) |
| upgrade-adoption-split | upgrade.md § Step 0b | 4 | not adopted (nothing staged), adopted (floor raised and staged), already ahead (floor unchanged), snapshot method (falls through) |
| verify-floor | verify.md § Adoption floor | 4 | no lock (not a fault), ahead of floor with extra plugins (not a fault), a shortfall (a fault), a floor plugin the marketplace no longer ships (a fault, not installed around) |
| step-reconcile | reconcile.md § The sweep | 3 | a clean sweep on a pinned-snapshot install (anchor present, config resolved — stamp written, nothing proposed), a renamed step heading stranding an override's anchor (one re-anchor proposal named), a marketplace install whose plugin cache is sandbox-denied (anchor resolution left `unchecked`, config resolution still completes) |
| step-reconcile | reconcile.md § The sweep | 5 | a clean sweep on a pinned-snapshot install (anchor present, config resolved — stamp written, nothing proposed), a renamed step heading stranding an override's anchor (one re-anchor proposal named), a marketplace install whose plugin cache is sandbox-denied (anchor resolution left `unchecked`, config resolution still completes), a configured security import policy with missing callers and operations (propose minimum grants, do not stamp clean), and a declined import-grant proposal that must not be stamped clean |
| step-reconcile-confirmation | reconcile.md § Step 2 — Confirm, apply, and write the stamp | 3 | declined grant, confirmed but unsaved policy, and saved policy with verified grants |
| step-verify | verify.md § 12. Latest available plugin version | 2 | a dev-to-dev delta where the marketplace clone is one dev build ahead of an installed plugin (`update_available` carries the newer dev version — pins decision 7: nothing strips `.devN`), and a sandbox-denied marketplace clone (`update_available: null` **and** `unchecked: ["latest-version"]`, distinguishing *nothing newer* from *could not look*) |
| step-config-stamp | config.md § Step 3b | 6 | `config` on an already-adopted project where Step 3 wrote the skill's last missing file this run, which records `acknowledged.skills` locally and never touches the committed lock; `config` on an unadopted one, whose entries land in the git-directory home's (`<git-common-dir>/apache-magpie/reconciled.json`) `skills` map with `version`/`at` regardless of whether this run touched a file; the R2 skip on a repo where nothing has ever been configured or adopted (`write_stamp: false`); and an already-adopted project where the one skill in scope was already fully configured *before* this run, so nothing is recorded even though the lock exists (`write_stamp: false` for a different reason — the narrowed acknowledged-write trigger); a linked worktree of an adopted project with no `.apache-magpie-local/` of its own, which records into the main checkout's (`write_location: main-checkout`); and a linked worktree of an unadopted clone, which records into the shared git-directory home (`write_location: git-dir`) |
| config-vcs-backend | config.md § Step 3g | 5 | an SVN working copy as the `<upstream>` clone beside a Git tracker repo (propose `vcs_backend: svn`, the URLs and `trunk`, written only on confirmation); a plain Git project (write `git`, ask nothing); a git-svn mirror on GitHub (propose svn with the repository root left `TODO`, say an `svn checkout` is needed, never run it); a checkout outside `trunk`/`branches`/`tags` (no default branch proposed); and an SVN checkout whose URLs could not be read (propose `svn`, leave both URLs `TODO` rather than guess) |
Expand Down Expand Up @@ -143,3 +144,14 @@ uv run --directory tools/skill-evals skill-eval --cli "claude -p" \
`update_available: null` with `unchecked: ["latest-version"]`, never
an empty list that a reader could mistake for "checked, nothing
found."

## Run history

Live model runs over this whole eval directory, newest first.
Generated from [`runs.jsonl`](runs.jsonl) by `skill-eval-journal render`;
do not edit the table by hand.
Columns and rules: [Recording runs](../../README.md#recording-runs).

| Date | Ref | Model | Runs | Result | Notes |
|---|---|---|---|---|---|
| 2026-11-02 | `5eb60e27` (fix/pr-1749-review-round2) | (unrecorded, `claude -p`) | 3 | `step-reconcile/case-2-stale-anchor` failed 1 of 2; `step-reconcile/case-4-import-policy-grants` failed 1 of 2 | |
Loading