fix(git-wrappers): remove the guessed-login credential path from pr-review and issue-comment
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
With no --login, both wrappers resolved a login by GUESSING it from the repo host (get_gitea_login_for_host / get_gitea_login), then looked that name up in ~/.config/tea/config.yml. On git.mosaicstack.dev the guess resolves to mosaicstack-mos-dt-0, a SHARED account. get_gitea_token_for_login returns the matching token string with no authentication check anywhere in its body, so it returns rc=0 for a dead credential and the `|| get_gitea_token` fallback never fires. The identity-aware resolver was unreachable on this path. Measured on git.mosaicstack.dev with MOSAIC_GIT_IDENTITY set: get_gitea_token_for_login <guessed> rc=0, token authenticates HTTP 401 get_gitea_token <host> rc=0, token authenticates HTTP 200 Control: the same endpoint with no credential returns 401. The dead token is what made this visible; it is not the defect. Had the shared token been alive, every seat's reviews and comments would have been authored by the shared account, making Gate-16 author-is-not-reviewer unenforceable across the fleet. A caller that passes no --login is asking to act as ITSELF, and the guess answered a question nobody asked. This removes the guess and its tea lookup from the no---login path in both wrappers. That path now resolves the acting identity's own credential via get_gitea_token, which fails loud on a fleet host when no identity resolves. That refusal is the correct outcome and is deliberately not fallen back from. Unchanged on purpose: - get_gitea_token_for_login keeps its behaviour and its 53 assert_token pins in test-gitea-login-resolution.sh. pr-edit.sh and the explicit --login branches still use it; --login remains the only way to reach the tea store. - No in-function verification was added. These wrappers verify every write by id-plus-author read-back against the credential-derived login, so a revoked token fails at the write with no misattribution. A GET /user pre-check would also hard-fail a live token scoped write:repository without read:user, which returns 403 while being fully comment-capable. Tests: 28 pass. test-issue-close-fail-closed.sh fails identically on pristine upstream (byte-identical output) and touches issue-close.sh, which this does not modify. The wrapper test harness inherits an ambient MOSAIC_GIT_IDENTITY into its sandbox HOME; tests were run with it unset. Adversarial review by fargo, who found that reordering alone is a no-op wherever MOSAIC_GIT_IDENTITY is unset, and that a 401/403 fail-closed pre-check would reject correctly-scoped live tokens.
This commit is contained in:
@@ -102,9 +102,17 @@ gitea_resolve_api_for_login() {
|
||||
return 1
|
||||
}
|
||||
else
|
||||
GITEA_API_TOKEN=$(get_gitea_token_for_login "$effective_login" "$host") \
|
||||
|| GITEA_API_TOKEN=$(get_gitea_token "$host") || {
|
||||
echo "Error: Gitea token not found for login '$effective_login' (comment write/read-back)" >&2
|
||||
# NO --login: the acting credential is this identity's own token and there
|
||||
# is deliberately no tea-config fallback. get_gitea_token_for_login matches
|
||||
# by login NAME and performs no authentication check, and with no --login
|
||||
# that name was a HOST GUESS resolving to a shared account. A live shared
|
||||
# token would therefore have authored every seat's comment as that
|
||||
# account, making Gate-16 author-is-not-reviewer unenforceable fleet-wide;
|
||||
# a dead one is only what made the defect visible. get_gitea_token fails
|
||||
# loud on a fleet host when no identity resolves, and that refusal is the
|
||||
# correct outcome, not a case to fall back from.
|
||||
GITEA_API_TOKEN=$(get_gitea_token "$host") || {
|
||||
echo "Error: no Gitea credential resolved for the acting identity on host '$host' (comment write/read-back). Set MOSAIC_GIT_IDENTITY=<agent-id>, or pass --login <name> to use a named tea credential." >&2
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
@@ -335,15 +343,12 @@ if [[ "$PLATFORM" == "github" ]]; then
|
||||
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT"
|
||||
echo "Added comment to GitHub issue #$ISSUE_NUMBER"
|
||||
elif [[ "$PLATFORM" == "gitea" ]]; then
|
||||
# Resolve the login this comment should be attributed to: the --login
|
||||
# override when given, otherwise the detected default for this repo's host.
|
||||
# A --login override always wins. Otherwise name this repo host's login only
|
||||
# as a best effort: the login name merely selects a per-login token, and
|
||||
# gitea_resolve_api_for_login falls back to the host credential
|
||||
# (get_gitea_token) when no tea login is named, so the default credential
|
||||
# still resolves even when the host tea has no matching login entry.
|
||||
# A --login override selects a NAMED tea credential and is the only way to
|
||||
# reach the tea store. With no --login there is deliberately no guess: the
|
||||
# comment is attributed to this identity's own credential, resolved by
|
||||
# gitea_resolve_api_for_login. The guess this replaced named a SHARED
|
||||
# account, selecting an identity the caller never asked to act as.
|
||||
EFFECTIVE_LOGIN="$LOGIN_OVERRIDE"
|
||||
[[ -n "$EFFECTIVE_LOGIN" ]] || EFFECTIVE_LOGIN=$(get_gitea_login 2>/dev/null || true)
|
||||
|
||||
# Bind the REST endpoint + token to the effective login, then derive the
|
||||
# acting identity from that SAME credential (GET /user). The write below and
|
||||
|
||||
Reference in New Issue
Block a user