No pr-edit wrapper: PR body/title edits force a raw PATCH or an identity compromise (pr-metadata is GET-only; issue-edit resolves login by first host match) #1047
Open
opened 2026-08-04 23:32:44 +00:00 by Mos
·
1 comment
No Branch/Tag Specified
main
greenfield/fomo-lin
feat/lease-promotion-and-harness-isolation
fix/1099-pipefail-wake
fix/1099-pipefail-tests
fix/1099-pipefail-sweep
fix/framework-shell-portability
fix/1043-pane-git-identity
fix/1081-issue-close-silent-comment-failure
fix/1090-enrollment-wallclock-tolerance
feat/1082-tea-stale-token-diagnostic
fix/detect-platform-silent-128-outside-repo
feat/1050-install-state-machine-red-fixture
fix/pr-merge-message-field
feat/1051-mosaic-brain-installer
feat/1045-mosaic-cred
remediation/state
fix/1056-upgrade-rollback-control-race
fix/1019-ci-queue-timeout-harness
next
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1047
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
There is no wrapper for editing a PR body/title, and the gap forces either a raw provider
PATCHor an identity compromise. Measured, not assumed:pr-metadata.shis GET-only — it normalises PR JSON; there is noPATCH/POST/PUTanywhere in it. (Its name suggests mutability; the body does not have it.)pr-create,pr-merge,pr-close,pr-review,pr-view,pr-diff,pr-list,pr-ci-wait,pr-metadata— and nopr-edit.issue-edit.shexists but is tea-only with zerocurl, resolving--loginby first host match — so it authors as whatever login happens to sort first for that host, which is the misattribution class of #1044.Why this bites: the authority gradient is inverted from the org chart
Enumerated from the provider with a negative control (a fabricated user returns does-not-exist, so the query discriminates):
Writes were being routed upward to the layer that cannot perform them. The intuitive assumption — "the coordinator can do more than a worker" — is backwards here, which is why the gap surfaced only at execution, three separate times in one shift.
The order-of-questions fix: (1) who already holds this right? → (2) can I? → (3) what needs granting? Asking (2)/(3) first leads to requesting a production credential widening for something an existing principal can already do. In the live case the answer to (1) was a field (
poster) on an API response already fetched twice — a PR body belongs to its poster, who can edit it as itself with no grant at all.Why a scoped grant is not the workaround
Gitea token scopes are coarse:
write:repositorycovers push AND pr-edit. There is no metadata-only scope, so "PR body and title only, no push" is not expressible on this provider — the nearest available grant hands over git-push authority too.Ask — a wrapper-backed PR body/title edit operation
pr-edit.sh(or equivalent) that:Important residual the wrapper must NOT overclaim
The provider exposes no editor identity on a PR/issue BODY. Even a perfectly authenticated
PATCHleaves no visible author — the write is unattributable, the content is verifiable. So the wrapper must report content-verified-by-read-back and must never emit authored-by-X-verified: the second is not checkable and must not be claimed. (This also correctly narrows the impersonation concern for bodies specifically — there is no author field to falsely populate, unlike a commit.)Provenance
Raised by a code reviewer that was explicitly invited to contest a documented one-off raw-
PATCHexception. Its disposition: acceptable for that single provider-only repair because no wrapper exists and the poster used its own scoped identity; must not become silent precedent; the durable fix is a wrapper-backed operation with identity and read-back enforcement. Filing so the exception stops being needed.Related: #1043 (identity lifecycle), #1044 (fail-open to shared credential), #1045 (
mosaic credepic).Binding the measurements: file hashes, and why they are here instead of a commit
ESTATE: CROSS — the tooling described here is HOMELAB code (
mosaicstack/stack), but every behaviour was measured against USC targets. The code is shared; the observed instances are not necessarily.The problem this comment fixes
The deployed tooling has no version to cite.
~/.config/mosaicis not a git repo — no ref, no commit, nothing a finding can be bound to. (Confirmed directly.) Worse, the framework version is not even locally single-valued: separate stack clones exist at different commits on the same host.Consequence, stated by the reporting agent better than I can:
A framework change lands upstream, every finding in this issue silently goes stale, and nothing in the record disagrees. A maintainer reading it later cannot tell whether it describes current code.
SHA-256 (first 12) of the deployed files these findings were measured against
tools/git/pr-metadata.shd088fe3f825ftools/git/issue-edit.sh5aacffa3f664tools/git/pr-merge.sh08a65e8584c5tools/git/detect-platform.sh02cdb2cf5ec2tools/git/ci-queue-wait.sh19cda2f7009ctools/_lib/credentials.sha108fab57896tools/tmux/agent-send.sha04eb80afd7dThree independent derivations agree on these (two agents derived them separately; a third re-derived all seven from the deployed copy and matched every one). They are a content binding, not a version — which is the point: they make staleness detectable even though the deployment carries no ref.
Standing rule adopted by the reporting lane
Applies beyond this issue
The same files underpin the measurements in #1043 (pane export allowlist), #1044 (
get_gitea_tokenfail-open), #1046 (codex review wrappers) and #1049 (interleaved tea logins). Treat the hashes above as the binding for those too, and re-derive before acting on any of them.Suggested framework fix, separate from this issue's ask
Give the deployed tooling a version stamp (embedded commit/tag written at install time, readable by the wrappers), so findings can bind to a ref rather than to content hashes. Content hashes are a workaround for a deployment that cannot say what it is.