owner_repo= forge writes bypass the foreign-primary guard (ADR 0019 only reasons about dir=) #418
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sixfold-space/madtea#418
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The foreign-primary guard (ADR 0019,
check-foreign-primary) and the local-git steering all reason about a LOCAL checkout: they resolve the target repo on disk and ask "is this a foreign primary? is it behind?". A content write carryingowner_repo=instead ofdir=-madt_filescreate/update/delete/batch, and any forge-only write path - commits straight to the remote over the API with no local checkout in the picture, so none of those guards engage.Concretely: an
owner_repo=create onto a repo whose local clone is unborn (a freshinit, or a clone that never fetched) while the forge already carries history. The write lands on the forge, the local checkout stays empty, and the two states silently disagree. That is the exact divergence the foreign-primary posture exists to prevent, reached through the one write path that never touches a checkout. Subtler variant: anowner_repo=write onto a branch whose local clone was last reconciled long ago.I want the
owner_repo=/ forge-API write path held to the same standard asdir=:owner_repo=write targets a repo that has a local checkout the caller is not going through.Design questions (this probably wants its own ADR, since it extends 0019):
madt_api_callraw passthrough cannot have a repo target reliably extracted from an arbitrary endpoint. Documented gap, or in scope?Severity is moderate, because the write still takes intent. But it is a real hole in the guard set, worth closing deliberately rather than leaving
owner_repo=as the unguarded write path.Where I have landed, and what is still open.
My plan: hold the
owner_repo=/ forge-API write path to the same reconcile-before-write standard asdir=, in the TOOL layer. A PreToolUse hook backstops only one client, so the durable fix belongs in the tool. Leavemadt_api_callraw passthrough as a documented gap, because no reliable repo target can be extracted from an arbitrary endpoint. This extends ADR 0019, so it wants its own ADR.Still open: the no-local-clone case. Nothing local can prove not-behind there, so the choice is refuse-and-require-an-explicit-confirm, or warn-and-proceed. My lean is fail closed and refuse, because that matches the rest of the guard set. The counter-argument is that a first write to a genuinely new repo is then always two steps. I want to settle this before drafting the ADR.
Decided: a non-overridable, tool-layer guard keyed on server-side forge state. No agent-settable confirm - an agent-flippable override is not a guard (ADR 0009). An unattended agent would just pass confirm=true and clobber, so consent cannot be the mechanism.
Rule for a forge-API content write via
owner_repo=with no reconciled local view:The guard keys on forge truth the agent cannot fake (is the target empty or populated), not on the agent's cooperation. This is the require-remote-verified pattern (block when the forge is populated and the local view is unborn/behind), but living in madtea's tool layer so it protects every MCP client, not just one host's PreToolUse hook. It extends ADR 0019 to the forge-API write path, which today reasons only about local checkouts.
Scope note: the
madt_api_callraw passthrough stays a documented gap - no reliable repo target is extractable from an arbitrary endpoint (consistent with ADR 0027 excluding the passthrough). This guard covers the typed content-write tools (madt_files, API-planemadt_commit,madt_branch_create, ...).This warrants its own ADR extending 0019. Clearing needs-decision.
hexajon referenced this issue2026-09-08 20:04:02 +00:00
Recorded in the design of record: ADR 0019 amendment (2026-09-08), merged in PR #471. This issue stays open for the tool-layer guard implementation (allow empty, refuse populated).