fix(git): fail closed on unquoted non-string YAML token scalars (#865)
Round-7 blocker-1 residual: the PyYAML-absent line-parser fallback in detect-platform.sh (_strip_scalar) returned a stringified scalar for UNQUOTED YAML values that PyYAML's implicit resolver types as a non-string (int/null/bool/float/timestamp). That bypassed _accept's isinstance(str) guard and could surface a garbage credential (e.g. "12345", "null", "true") where the PyYAML path resolves NO token and fails closed -- violating the module invariant that the fallback is only ever MORE conservative than PyYAML, never less. Root cause fix: mirror PyYAML 6.0.3's SafeLoader implicit resolver. An unquoted plain scalar matching the null/bool/int/float/timestamp forms now returns None (fail closed); a quoted scalar is always a string and is accepted verbatim (quote-stripped) as before. Quoted-string handling, scope-aware attribution, indentation, and inline-comment stripping are unchanged. The predicate was fuzzed against real PyYAML over ~800k random tokens with zero fail-open divergences. Extends the forced-PyYAML-absence parser-equivalence harness with token: 12345/null/~/yes/true/3.14 (each fails closed identically to PyYAML) and token: "12345"/'abc' (quoted literals still accepted). Blockers 2/3/4 (port-bound host, origin+full-path URL pin, review-body binding) are untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -440,4 +440,41 @@ write_fixture 'logins:
|
||||
assert_token "implicit https vs explicit :443 match" "TOK_DEFPORT" defported git.example:443
|
||||
assert_token "implicit https vs :8443 rejected" "" defported git.example:8443
|
||||
|
||||
# 8. An UNQUOTED token whose raw text PyYAML's implicit resolver types as a
|
||||
# NON-string (int / null / bool / float) must fail closed: PyYAML yields a
|
||||
# non-str value that _accept rejects, so the fallback must NOT surface the
|
||||
# stringified scalar as a credential. Each raw form fails closed IDENTICALLY
|
||||
# to PyYAML (a prior residual emitted "12345"/"null"/"true"/etc. here).
|
||||
assert_nonstring_token_fails_closed() {
|
||||
local desc="$1" raw="$2"
|
||||
write_fixture "logins:
|
||||
- name: primary
|
||||
url: https://git.example
|
||||
token: ${raw}
|
||||
"
|
||||
assert_token "$desc" "" primary git.example
|
||||
}
|
||||
assert_nonstring_token_fails_closed "unquoted int token fails closed" "12345"
|
||||
assert_nonstring_token_fails_closed "unquoted null token fails closed" "null"
|
||||
assert_nonstring_token_fails_closed "unquoted tilde-null token fails closed" "~"
|
||||
assert_nonstring_token_fails_closed "unquoted yes(bool) token fails closed" "yes"
|
||||
assert_nonstring_token_fails_closed "unquoted true(bool) token fails closed" "true"
|
||||
assert_nonstring_token_fails_closed "unquoted float token fails closed" "3.14"
|
||||
|
||||
# 9. A QUOTED scalar is ALWAYS a string, even when its contents look like a
|
||||
# non-string implicit form. The quotes force str typing in PyYAML, so the
|
||||
# fallback must accept the literal (quote-stripped) contents as the token.
|
||||
write_fixture 'logins:
|
||||
- name: primary
|
||||
url: https://git.example
|
||||
token: "12345"
|
||||
'
|
||||
assert_token "double-quoted digit token is a literal string" "12345" primary git.example
|
||||
write_fixture "logins:
|
||||
- name: primary
|
||||
url: https://git.example
|
||||
token: 'abc'
|
||||
"
|
||||
assert_token "single-quoted token is a literal string" "abc" primary git.example
|
||||
|
||||
echo "Gitea login resolution regression harness passed"
|
||||
|
||||
Reference in New Issue
Block a user