Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions loopx/public_safe_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,26 @@
PRESENTATION_EXTENDED_WINDOWS_PATH_PATTERN,
PRESENTATION_COLON_PREFIXED_WINDOWS_PATH_PATTERN,
)
# The provider-issued credential shapes, as one alternation body shared by every
# owner that has to recognize a token with no label at all. A prefix carries the
# provider's own issuer identity, so the shape is self-describing and a caller
# never has to guess a label; the length floor keeps ordinary prose out. Case
# folding is left to the consumer's compile flags or inline `(?i)`, so this
# string stays a plain alternation instead of owning one flag decision.
#
# Kept here rather than restated per caller: a scan that recognizes only some
# issuers certifies the rest as public-safe, and copies drift (Refs #5136).
PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE = (
r"\bgh[pousr]_[a-z0-9]{16,}\b|"
r"\bgithub_pat_[a-z0-9_]{20,}|"
r"\b(?:akia|asia)[a-z0-9]{16}\b|"
r"\bxox[baprs]-[a-z0-9-]{10,}|"
r"\baiza[a-z0-9_-]{20,}|"
r"\b(?:sk|rk)_(?:live|test)_[a-z0-9]{12,}|"
r"\bnpm_[a-z0-9]{20,}|"
r"\bpypi-[a-z0-9_-]{20,}|"
r"\beyj[a-z0-9_-]{10,}\.[a-z0-9_-]{10,}\.[a-z0-9_-]{10,}\b"
)
PRESENTATION_PUBLIC_BOUNDARY_PATTERNS: tuple[
tuple[str, re.Pattern[str]], ...
] = (
Expand All @@ -311,31 +331,19 @@
re.IGNORECASE,
),
),
# An issuer prefix is its own label: a token carried in tool output or a
# pasted log rarely arrives as an assignment, so the assignment arm never
# sees it. Composed from the shared source the sibling scanners consume
# (#7636), case-folded like the presentation local-path arms.
(
"provider token",
re.compile(r"(?i)(?:" + PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE + r")"),
),
)
# Refs #5136: one definition for "this string carries a raw remote location".
# Three validators each restated the same scheme list, and the canonical
# public-safety owner had no counterpart, so a fourth caller had to invent one.
REMOTE_LOCATION_SURFACE_PATTERN = re.compile(r"(?i)\b(?:https?|file|s3|gs|tos|hdfs)://")
# The provider-issued credential shapes, as one alternation body shared by every
# owner that has to recognize a token with no label at all. A prefix carries the
# provider's own issuer identity, so the shape is self-describing and a caller
# never has to guess a label; the length floor keeps ordinary prose out. Case
# folding is left to the consumer's compile flags or inline `(?i)`, so this
# string stays a plain alternation instead of owning one flag decision.
#
# Kept here rather than restated per caller: a scan that recognizes only some
# issuers certifies the rest as public-safe, and copies drift (Refs #5136).
PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE = (
r"\bgh[pousr]_[a-z0-9]{16,}\b|"
r"\bgithub_pat_[a-z0-9_]{20,}|"
r"\b(?:akia|asia)[a-z0-9]{16}\b|"
r"\bxox[baprs]-[a-z0-9-]{10,}|"
r"\baiza[a-z0-9_-]{20,}|"
r"\b(?:sk|rk)_(?:live|test)_[a-z0-9]{12,}|"
r"\bnpm_[a-z0-9]{20,}|"
r"\bpypi-[a-z0-9_-]{20,}|"
r"\beyj[a-z0-9_-]{10,}\.[a-z0-9_-]{10,}\.[a-z0-9_-]{10,}\b"
)
SECRET_LIKE_SURFACE_PATTERN = re.compile(
r"(?i)(?:\bbearer\s+[a-z0-9._~+/=-]{16,}|"
r"\b(?:access|api|secret)[_-]?key[\"']?\s*[=:]\s*[\"']?[^\s`'\"<>]+|"
Expand Down
50 changes: 50 additions & 0 deletions tests/control_plane/test_presentation_public_safety.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,53 @@ def test_colon_prefixed_unix_paths_keep_the_existing_boundary() -> None:
"ok": False,
"warnings": ["absolute local path"],
}


@pytest.mark.parametrize(
"token",
[
"ghp_" + "A1b2C3d4E5f6G7h8I9j0K1l2M3n4",
"github_pat_11ABCDEFG0" + "a1B2c3D4e5F6",
"AKIA" + "7Q2Z3XJ5V6N8W1PL",
"ASIA" + "7Q2Z3XJ5V6N8W1PL",
"xoxb-" + "123456789-abcdef",
"AIzaSyA" + "1234567890abcdefghij",
"sk_live_51H8" + "aBcDeFgHiJkL",
"npm_" + "a1B2c3D4e5F6g7H8i9J0",
"pypi-AgEIcHlwaS5vcmc" + "AAAAAAAAAA",
"eyJhbGciOiJIUzI1NiJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIn0" + ".SflKxwRJSMeKKF2QT4f",
],
)
def test_unlabeled_provider_tokens_fail_the_boundary_scan(token: str) -> None:
text = f"CI log fragment: pushed with {token} to the registry mirror"

assert public_safety.scan_public_boundary_text(text) == {
"ok": False,
"warnings": ["provider token"],
}


@pytest.mark.parametrize(
"text",
[
"npm run build && npm test",
"gh pr list --limit 5",
"AWS key ids start AKIA and ASIA, then sixteen more characters",
"pypi- prefix alone is not a token",
"sk-proj-abcdefghijklmnop is an OpenAI project key shape",
],
)
def test_ordinary_prose_and_unclaimed_shapes_stay_public(text: str) -> None:
assert public_safety.scan_public_boundary_text(text) == {
"ok": True,
"warnings": [],
}


def test_labeled_credential_assignment_keeps_its_own_warning() -> None:
text = "deploy used access_token=ghp_" + "A1b2C3d4E5f6G7h8I9j0K1l2M3n4"

result = public_safety.scan_public_boundary_text(text)

assert result["ok"] is False
assert result["warnings"] == ["credential assignment", "provider token"]
Loading