Adds an opt-in per-agent Gitea identity so a fleet agent can push/commit/open PRs under its own token instead of the single shared account, giving cryptographic author-!=-reviewer separation (Gate-16).
What changed
tools/git/git-credential-mosaic (new) - a git credential helper (get verb). Identity resolution priority: MOSAIC_GIT_IDENTITY env -> git config --get mosaic.gitIdentity (per-worktree, persists on disk) -> git-supplied username. If the resolved identity has a per-slot token file ~/.config/mosaic/secrets/gitea-tokens/gitea-{usc,mosaicstack}-.token, emits username= + that token; else falls back to the existing shared-account path unchanged.
tools/git/detect-platform.sh get_gitea_token() - the API-tooling counterpart (pr-create.sh, issue-create.sh, ...): a small block resolving the same identity (env -> git config) prepended ahead of the existing shared-token logic, so PRs/issues open under the resolved agent identity too.
install.sh - git-credential-mosaic ships without a .sh suffix (git resolves credential helpers by name/path, not extension), so it needs an explicit chmod +x alongside the existing .sh glob. tools/* is already framework-owned, so the file syncs to ~/.config/mosaic/tools/git/ on install/update automatically - no manifest change needed.
tools/git/README.md - documents the feature, the one-time git config credential.helper registration step (deliberately NOT auto-wired on install - see the README for why), and the PowerShell-parity decision (detect-platform.ps1 authenticates via tea logins, not a raw-token function, so there is nothing to port there; a native PS credential-helper is not needed either, since Git for Windows invokes credential.helper via its bundled sh).
Backward compatibility
No-op on any host without per-slot tokens configured: both tools fall through to the exact existing shared-account path when no per-slot token file is found for the resolved (or absent) identity. Proven by test-git-credential-mosaic.sh (case: no per-slot token -> shared fallback) and test-gitea-token-identity.sh (same, for get_gitea_token).
Tests (red-first)
New harnesses (mirroring the existing test-*.sh style in this directory - stubbed token files + a fake HOME, never touching real ~/.config/mosaic/secrets):
tools/git/test-gitea-token-identity.sh - same priority/fallback/cross-host coverage for get_gitea_token().
Both verified red against the pre-patch code (manually diffed back to origin/main detect-platform.sh and a shared-only git-credential-mosaic) before the patch made them green. Wired into package.json test:framework-shell (which pnpm test runs).
Quality gates run
shellcheck -x -e SC1090 on all new/changed shell files: clean.
pnpm --filter @mosaicstack/mosaic test:framework-shell: all scenarios pass, including the two new harnesses.
pnpm --filter @mosaicstack/mosaic lint: clean.
tools/quality/scripts/verify-sanitized.sh: clean (the vetted kit fallback username was replaced with a generic placeholder - see commit message).
Full pre-push hook (repo-wide typecheck + lint + format:check via turbo): green.
Upstreams Mos host-local tooling-patch kit (2026-07-23), Patches 1+2.
Adds an opt-in per-agent Gitea identity so a fleet agent can push/commit/open PRs under its own token instead of the single shared account, giving cryptographic author-!=-reviewer separation (Gate-16).
## What changed
tools/git/git-credential-mosaic (new) - a git credential helper (get verb). Identity resolution priority: MOSAIC_GIT_IDENTITY env -> git config --get mosaic.gitIdentity (per-worktree, persists on disk) -> git-supplied username. If the resolved identity has a per-slot token file ~/.config/mosaic/secrets/gitea-tokens/gitea-{usc,mosaicstack}-<id>.token, emits username=<id> + that token; else falls back to the existing shared-account path unchanged.
tools/git/detect-platform.sh get_gitea_token() - the API-tooling counterpart (pr-create.sh, issue-create.sh, ...): a small block resolving the same identity (env -> git config) prepended ahead of the existing shared-token logic, so PRs/issues open under the resolved agent identity too.
install.sh - git-credential-mosaic ships without a .sh suffix (git resolves credential helpers by name/path, not extension), so it needs an explicit chmod +x alongside the existing *.sh glob. tools/** is already framework-owned, so the file syncs to ~/.config/mosaic/tools/git/ on install/update automatically - no manifest change needed.
tools/git/README.md - documents the feature, the one-time git config credential.helper registration step (deliberately NOT auto-wired on install - see the README for why), and the PowerShell-parity decision (detect-platform.ps1 authenticates via tea logins, not a raw-token function, so there is nothing to port there; a native PS credential-helper is not needed either, since Git for Windows invokes credential.helper via its bundled sh).
## Backward compatibility
No-op on any host without per-slot tokens configured: both tools fall through to the exact existing shared-account path when no per-slot token file is found for the resolved (or absent) identity. Proven by test-git-credential-mosaic.sh (case: no per-slot token -> shared fallback) and test-gitea-token-identity.sh (same, for get_gitea_token).
## Tests (red-first)
New harnesses (mirroring the existing test-*.sh style in this directory - stubbed token files + a fake HOME, never touching real ~/.config/mosaic/secrets):
- tools/git/test-git-credential-mosaic.sh - identity-resolution priority (env > git-config > username), per-host token path selection, shared fallback, cross-host non-leak, unknown-host passthrough.
- tools/git/test-gitea-token-identity.sh - same priority/fallback/cross-host coverage for get_gitea_token().
Both verified red against the pre-patch code (manually diffed back to origin/main detect-platform.sh and a shared-only git-credential-mosaic) before the patch made them green. Wired into package.json test:framework-shell (which pnpm test runs).
## Quality gates run
- shellcheck -x -e SC1090 on all new/changed shell files: clean.
- pnpm --filter @mosaicstack/mosaic test:framework-shell: all scenarios pass, including the two new harnesses.
- pnpm --filter @mosaicstack/mosaic lint: clean.
- tools/quality/scripts/verify-sanitized.sh: clean (the vetted kit fallback username was replaced with a generic placeholder - see commit message).
- Full pre-push hook (repo-wide typecheck + lint + format:check via turbo): green.
Upstreams Mos host-local tooling-patch kit (2026-07-23), Patches 1+2.
Closes #873
Adds an opt-in per-agent Gitea identity so a fleet agent can push/commit/open
PRs under its own token instead of the single shared account, giving
cryptographic author-!=-reviewer separation (Gate-16).
Resolution priority (both tools): MOSAIC_GIT_IDENTITY env > git config
mosaic.gitIdentity (per-worktree, persists on disk) > git-supplied username
(git-credential-mosaic only). If the resolved identity has a token file at
~/.config/mosaic/secrets/gitea-tokens/gitea-{usc,mosaicstack}-<id>.token, that
identity is used; otherwise both tools fall through to the existing
shared-account path unchanged, so this is a no-op on any host without
per-slot tokens configured.
- tools/git/git-credential-mosaic: new git credential helper (get verb).
- tools/git/detect-platform.sh: get_gitea_token() gains the same identity
resolution, prepended ahead of the existing shared-token logic, so API
tooling (pr-create.sh, issue-create.sh, ...) authors under the same
identity as git push/fetch.
- install.sh: explicit chmod +x for git-credential-mosaic (it ships without
a .sh suffix, so the existing *.sh glob does not cover it); tools/** is
already framework-owned so the file syncs automatically.
- tools/git/README.md: documents the feature, the one-time
`git config credential.helper` registration step (deliberately not
auto-wired — see README for why), and the PowerShell-parity decision
(detect-platform.ps1 authenticates via tea logins, not a raw-token
function, so there is nothing to port there).
- tools/git/test-git-credential-mosaic.sh,
tools/git/test-gitea-token-identity.sh: new regression harnesses (red
verified against the pre-patch code) covering identity-resolution
priority, per-host token path selection, and shared-account fallback.
Wired into package.json's test:framework-shell.
Upstreams Mos host-local tooling-patch kit (2026-07-23), Patches 1+2.
Closes#873
Co-Authored-By: Claude Opus 4.8 <[email protected]>
core.filemode=false in this worktree meant the initial commit recorded
git-credential-mosaic, test-git-credential-mosaic.sh, and
test-gitea-token-identity.sh as 100644. git invokes a path-configured
credential.helper directly (exec, not `sh <path>`), so git-credential-mosaic
must carry the executable bit; the two test scripts match the 100755
convention already used by the other test-*.sh harnesses in this directory.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Unrelated to the per-agent-identity feature in this branch. The repo's
format:check gate (which the pre-push hook runs across the whole tree) was
already failing against origin/main on this file before this branch existed;
fixing it here only because it otherwise blocks pushing this PR. No content
change — table alignment/spacing only.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Gate-16 APPROVE -- stamped by Mos (id-11) -- FINAL of the framework train
Registered under the distinct Mos bot (id-11): PR author jason.woltje(id2) != approver Mos(id11). Commit-author now = mosaic-coder (the (c) durable builder identity) != reviewer ms-lead-reviewer -> Finding-0 ELIMINATED (not documented-around). Registers the independent reviewer's FINALIZED APPROVE at the re-authored head; MS-LEAD prepared/relayed, Mos stamps+merges.
INTEGRITY STORY: the original review (@f068a54a) was REQUEST-CHANGES -- the reviewer refused to certify author!=reviewer while the commit AUTHOR literally read ms-lead-reviewer, and verified the merges from first principles (not the coordinator's narrative). Mos (gate authority) ruled (a) RE-AUTHOR -- declining to stamp-over a principled REQUEST-CHANGES -- applying the durable (c) fix retroactively. Commits re-authored to mosaic-coder (metadata-only).
AUTHOR-BLOCKER DISSOLVED (confirmed): both commits author=committer=mosaic-coder != reviewer -> independence certifiable. CODE UNCHANGED vs the prior tech-approved f068a54a (confirmed 3 ways): git diff empty; IDENTICAL tree hash 79e6bed18c868663f1dd205e6e9d92d9bbdc76ce; range-diff shows only the Author line, identical stable patch-ids. All technical findings carry + re-verified green (test:framework-shell pass, firewall clean, backward-compat no-op).
6-CHECK re-verified by Mos @4b472a22425692cf8d60d94e6b46a7533ed7c113: open/not-merged/mergeable onto main 85042169/base main; CI terminal-green wp1985 @exact head; reviewed==CI==head; independent APPROVE author!=reviewer no REQUEST-CHANGES; body 'Closes #873'; queue-guard clear. Clean commit-author (no Finding-0).
## Gate-16 APPROVE -- stamped by Mos (id-11) -- FINAL of the framework train
Registered under the distinct Mos bot (id-11): PR author jason.woltje(id2) != approver Mos(id11). Commit-author now = mosaic-coder (the (c) durable builder identity) != reviewer ms-lead-reviewer -> Finding-0 ELIMINATED (not documented-around). Registers the independent reviewer's FINALIZED APPROVE at the re-authored head; MS-LEAD prepared/relayed, Mos stamps+merges.
VERDICT: APPROVE @ 4b472a22425692cf8d60d94e6b46a7533ed7c113 (Closes #873 -- per-agent Gitea identity, PR-B).
INTEGRITY STORY: the original review (@f068a54a) was REQUEST-CHANGES -- the reviewer refused to certify author!=reviewer while the commit AUTHOR literally read ms-lead-reviewer, and verified the merges from first principles (not the coordinator's narrative). Mos (gate authority) ruled (a) RE-AUTHOR -- declining to stamp-over a principled REQUEST-CHANGES -- applying the durable (c) fix retroactively. Commits re-authored to mosaic-coder (metadata-only).
AUTHOR-BLOCKER DISSOLVED (confirmed): both commits author=committer=mosaic-coder != reviewer -> independence certifiable. CODE UNCHANGED vs the prior tech-approved f068a54a (confirmed 3 ways): git diff empty; IDENTICAL tree hash 79e6bed18c868663f1dd205e6e9d92d9bbdc76ce; range-diff shows only the Author line, identical stable patch-ids. All technical findings carry + re-verified green (test:framework-shell pass, firewall clean, backward-compat no-op).
6-CHECK re-verified by Mos @4b472a22425692cf8d60d94e6b46a7533ed7c113: open/not-merged/mergeable onto main 85042169/base main; CI terminal-green wp1985 @exact head; reviewed==CI==head; independent APPROVE author!=reviewer no REQUEST-CHANGES; body 'Closes #873'; queue-guard clear. Clean commit-author (no Finding-0).
Ghost
merged commit 4422231bdb into main2026-07-23 18:09:35 +00:00
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.
Adds an opt-in per-agent Gitea identity so a fleet agent can push/commit/open PRs under its own token instead of the single shared account, giving cryptographic author-!=-reviewer separation (Gate-16).
What changed
tools/git/git-credential-mosaic (new) - a git credential helper (get verb). Identity resolution priority: MOSAIC_GIT_IDENTITY env -> git config --get mosaic.gitIdentity (per-worktree, persists on disk) -> git-supplied username. If the resolved identity has a per-slot token file ~/.config/mosaic/secrets/gitea-tokens/gitea-{usc,mosaicstack}-.token, emits username= + that token; else falls back to the existing shared-account path unchanged.
tools/git/detect-platform.sh get_gitea_token() - the API-tooling counterpart (pr-create.sh, issue-create.sh, ...): a small block resolving the same identity (env -> git config) prepended ahead of the existing shared-token logic, so PRs/issues open under the resolved agent identity too.
install.sh - git-credential-mosaic ships without a .sh suffix (git resolves credential helpers by name/path, not extension), so it needs an explicit chmod +x alongside the existing .sh glob. tools/* is already framework-owned, so the file syncs to ~/.config/mosaic/tools/git/ on install/update automatically - no manifest change needed.
tools/git/README.md - documents the feature, the one-time git config credential.helper registration step (deliberately NOT auto-wired on install - see the README for why), and the PowerShell-parity decision (detect-platform.ps1 authenticates via tea logins, not a raw-token function, so there is nothing to port there; a native PS credential-helper is not needed either, since Git for Windows invokes credential.helper via its bundled sh).
Backward compatibility
No-op on any host without per-slot tokens configured: both tools fall through to the exact existing shared-account path when no per-slot token file is found for the resolved (or absent) identity. Proven by test-git-credential-mosaic.sh (case: no per-slot token -> shared fallback) and test-gitea-token-identity.sh (same, for get_gitea_token).
Tests (red-first)
New harnesses (mirroring the existing test-*.sh style in this directory - stubbed token files + a fake HOME, never touching real ~/.config/mosaic/secrets):
Both verified red against the pre-patch code (manually diffed back to origin/main detect-platform.sh and a shared-only git-credential-mosaic) before the patch made them green. Wired into package.json test:framework-shell (which pnpm test runs).
Quality gates run
Upstreams Mos host-local tooling-patch kit (2026-07-23), Patches 1+2.
Closes #873
Adds an opt-in per-agent Gitea identity so a fleet agent can push/commit/open PRs under its own token instead of the single shared account, giving cryptographic author-!=-reviewer separation (Gate-16). Resolution priority (both tools): MOSAIC_GIT_IDENTITY env > git config mosaic.gitIdentity (per-worktree, persists on disk) > git-supplied username (git-credential-mosaic only). If the resolved identity has a token file at ~/.config/mosaic/secrets/gitea-tokens/gitea-{usc,mosaicstack}-<id>.token, that identity is used; otherwise both tools fall through to the existing shared-account path unchanged, so this is a no-op on any host without per-slot tokens configured. - tools/git/git-credential-mosaic: new git credential helper (get verb). - tools/git/detect-platform.sh: get_gitea_token() gains the same identity resolution, prepended ahead of the existing shared-token logic, so API tooling (pr-create.sh, issue-create.sh, ...) authors under the same identity as git push/fetch. - install.sh: explicit chmod +x for git-credential-mosaic (it ships without a .sh suffix, so the existing *.sh glob does not cover it); tools/** is already framework-owned so the file syncs automatically. - tools/git/README.md: documents the feature, the one-time `git config credential.helper` registration step (deliberately not auto-wired — see README for why), and the PowerShell-parity decision (detect-platform.ps1 authenticates via tea logins, not a raw-token function, so there is nothing to port there). - tools/git/test-git-credential-mosaic.sh, tools/git/test-gitea-token-identity.sh: new regression harnesses (red verified against the pre-patch code) covering identity-resolution priority, per-host token path selection, and shared-account fallback. Wired into package.json's test:framework-shell. Upstreams Mos host-local tooling-patch kit (2026-07-23), Patches 1+2. Closes #873 Co-Authored-By: Claude Opus 4.8 <[email protected]>69092718d3tof068a54a8df068a54a8dto4b472a2242Gate-16 APPROVE -- stamped by Mos (id-11) -- FINAL of the framework train
Registered under the distinct Mos bot (id-11): PR author jason.woltje(id2) != approver Mos(id11). Commit-author now = mosaic-coder (the (c) durable builder identity) != reviewer ms-lead-reviewer -> Finding-0 ELIMINATED (not documented-around). Registers the independent reviewer's FINALIZED APPROVE at the re-authored head; MS-LEAD prepared/relayed, Mos stamps+merges.
VERDICT: APPROVE @
4b472a2242(Closes #873 -- per-agent Gitea identity, PR-B).INTEGRITY STORY: the original review (@f068a54a) was REQUEST-CHANGES -- the reviewer refused to certify author!=reviewer while the commit AUTHOR literally read ms-lead-reviewer, and verified the merges from first principles (not the coordinator's narrative). Mos (gate authority) ruled (a) RE-AUTHOR -- declining to stamp-over a principled REQUEST-CHANGES -- applying the durable (c) fix retroactively. Commits re-authored to mosaic-coder (metadata-only).
AUTHOR-BLOCKER DISSOLVED (confirmed): both commits author=committer=mosaic-coder != reviewer -> independence certifiable. CODE UNCHANGED vs the prior tech-approved
f068a54a(confirmed 3 ways): git diff empty; IDENTICAL tree hash 79e6bed18c868663f1dd205e6e9d92d9bbdc76ce; range-diff shows only the Author line, identical stable patch-ids. All technical findings carry + re-verified green (test:framework-shell pass, firewall clean, backward-compat no-op).6-CHECK re-verified by Mos @4b472a22425692cf8d60d94e6b46a7533ed7c113: open/not-merged/mergeable onto main 85042169/base main; CI terminal-green wp1985 @exact head; reviewed==CI==head; independent APPROVE author!=reviewer no REQUEST-CHANGES; body 'Closes #873'; queue-guard clear. Clean commit-author (no Finding-0).