fix(tools): use top-level tea comment invocation and formalize --login passthrough (#865) #866
@@ -598,6 +598,55 @@ repo_host = os.environ.get("REPO_HOST", "").strip().lower()
|
||||
config_path = sys.argv[1]
|
||||
|
||||
|
||||
# PyYAML 6.0.3 SafeLoader implicit resolver patterns (YAML 1.1). An UNQUOTED
|
||||
# plain scalar matching any of these is resolved by PyYAML to a NON-string type
|
||||
# (null->None, bool, int, float, timestamp->date/datetime); a quoted scalar is
|
||||
# ALWAYS a string. These mirror yaml/resolver.py so the PyYAML-absent fallback
|
||||
# types unquoted scalars exactly as PyYAML would (see _implicit_nonstring).
|
||||
_IMPLICIT_NULL = re.compile(r"^(?:~|null|Null|NULL|)$")
|
||||
_IMPLICIT_BOOL = re.compile(
|
||||
r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE"
|
||||
r"|on|On|ON|off|Off|OFF)$"
|
||||
)
|
||||
_IMPLICIT_INT = re.compile(
|
||||
r"^(?:[-+]?0b[0-1_]+"
|
||||
r"|[-+]?0[0-7_]+"
|
||||
r"|[-+]?(?:0|[1-9][0-9_]*)"
|
||||
r"|[-+]?0x[0-9a-fA-F_]+"
|
||||
r"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"
|
||||
)
|
||||
_IMPLICIT_FLOAT = re.compile(
|
||||
r"^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+]?[0-9]+)?"
|
||||
r"|\.[0-9][0-9_]*(?:[eE][-+]?[0-9]+)?"
|
||||
r"|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*"
|
||||
r"|[-+]?\.(?:inf|Inf|INF)"
|
||||
r"|\.(?:nan|NaN|NAN))$"
|
||||
)
|
||||
_IMPLICIT_TIMESTAMP = re.compile(
|
||||
r"^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
|
||||
r"|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?"
|
||||
r"(?:[Tt]|[ \t]+)[0-9][0-9]?"
|
||||
r":[0-9][0-9]:[0-9][0-9](?:\.[0-9]*)?"
|
||||
r"(?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$"
|
||||
)
|
||||
|
||||
|
||||
def _implicit_nonstring(text):
|
||||
# True when an UNQUOTED plain scalar would be resolved by PyYAML's SafeLoader
|
||||
# to a non-string type (null/bool/int/float/timestamp). Fuzzed against real
|
||||
# PyYAML 6.0.3: it never returns False where PyYAML types the scalar as a
|
||||
# non-string (i.e. never fail-open), and is at worst MORE conservative on a
|
||||
# couple of degenerate float spellings (e.g. "4.e8") that PyYAML keeps as a
|
||||
# string -- the safe direction for this credential-selecting fallback.
|
||||
return bool(
|
||||
_IMPLICIT_NULL.match(text)
|
||||
or _IMPLICIT_BOOL.match(text)
|
||||
or _IMPLICIT_INT.match(text)
|
||||
or _IMPLICIT_FLOAT.match(text)
|
||||
or _IMPLICIT_TIMESTAMP.match(text)
|
||||
)
|
||||
|
||||
|
||||
def _strip_scalar(value):
|
||||
# Resolve a YAML flow scalar the way PyYAML would for tea's simple scalars:
|
||||
# honor surrounding quotes and strip a trailing inline comment. A quoted
|
||||
@@ -605,6 +654,16 @@ def _strip_scalar(value):
|
||||
# an unquoted scalar ends at the first whitespace-preceded '#' (a YAML
|
||||
# comment must be preceded by whitespace or line start), so "abc#def" stays
|
||||
# literal while "abc # note" becomes "abc".
|
||||
#
|
||||
# A quoted scalar is ALWAYS a string, so its contents are returned verbatim.
|
||||
# An UNQUOTED scalar, however, is subject to PyYAML's implicit typing: forms
|
||||
# like `12345`, `null`, `~`, `yes`/`true`, `3.14` or a timestamp resolve to a
|
||||
# non-string (int/None/bool/float/date), which PyYAML's path would reject as
|
||||
# a token via _accept's isinstance(str) guard. To stay faithful (and never
|
||||
# fail OPEN by surfacing a stringified non-string as a credential) such a
|
||||
# scalar returns None here so the caller treats it as absent (fail closed),
|
||||
# exactly as the PyYAML path does. Only unquoted scalars PyYAML would type as
|
||||
# a string are returned as a string.
|
||||
value = value.strip()
|
||||
if not value:
|
||||
return value
|
||||
@@ -620,7 +679,12 @@ def _strip_scalar(value):
|
||||
if char == "#" and (index == 0 or value[index - 1] in (" ", "\t")):
|
||||
value = value[:index]
|
||||
break
|
||||
return value.strip()
|
||||
value = value.strip()
|
||||
if not value or _implicit_nonstring(value):
|
||||
# Unquoted scalar that PyYAML resolves to null or another non-string
|
||||
# type: fail closed rather than emit a stringified non-credential.
|
||||
return None
|
||||
return value
|
||||
|
||||
|
||||
def _url_matches_repo_host(url):
|
||||
|
||||
@@ -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