From f283171e2e655fad649a18324554dc8d8b6be007 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 7 Oct 2026 01:26:28 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=EB=A6=AC=ED=8F=AC=EC=A7=80=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=9D=B4=EB=A6=84=20=EC=A0=95=EA=B7=9C=EC=8B=9D?= =?UTF-8?q?=EC=9D=98=20=EA=B2=BD=EB=A1=9C=20=EC=A1=B0=EC=9E=91=20=EC=B7=A8?= =?UTF-8?q?=EC=95=BD=EC=A0=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/ci/actions_queue_health_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/actions_queue_health_core.py b/scripts/ci/actions_queue_health_core.py index ab600efdbc..ea90f26135 100644 --- a/scripts/ci/actions_queue_health_core.py +++ b/scripts/ci/actions_queue_health_core.py @@ -17,7 +17,7 @@ from pathlib import Path from typing import Any -REPOSITORY_PATTERN = re.compile(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") +REPOSITORY_PATTERN = re.compile(r"^(?!.*(?:\.\.|\.$))[A-Za-z0-9_.-]+/(?!.*(?:\.\.|\.$))[A-Za-z0-9_.-]+$") QUEUE_STATES = {"QUEUED", "IN_PROGRESS", "PENDING", "REQUESTED"} TERMINAL_STATES = {"COMPLETED"} DEFAULT_QUEUE_AGE_SLO_SECONDS = 900 From c3963dc885fa3438c62f944467ba4c35d45c91de Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 13:03:11 +0900 Subject: [PATCH 2/5] test(queue-health): reproduce owner trailing-dot validation gap --- tests/test_actions_queue_health.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/test_actions_queue_health.py b/tests/test_actions_queue_health.py index dcf2f6f87c..ff1f4cfbf7 100644 --- a/tests/test_actions_queue_health.py +++ b/tests/test_actions_queue_health.py @@ -141,13 +141,31 @@ def test_parse_timestamp_normalises_z_and_offsets() -> None: assert queue_health.parse_timestamp("2026-08-19T21:00:00+09:00") == NOW -@pytest.mark.parametrize("value", ["owner", "owner/repo/extra", "../..", "./repo", "owner/.", 1]) +@pytest.mark.parametrize( + "value", + [ + "owner", + "owner/repo/extra", + "../..", + "./repo", + "owner/.", + "owner./repo", + "owner/repo.", + 1, + ], +) def test_repository_name_rejects_non_repository_identifiers(value: object) -> None: """Reject malformed and traversal-like repository identifiers.""" with pytest.raises(queue_health.QueueHealthError): queue_health._repository_name(value) +@pytest.mark.parametrize("value", [".github/repo", "owner/.github", "owner-name/repo_name"]) +def test_repository_name_accepts_safe_identifiers(value: str) -> None: + """Accept safe GitHub owner/repository identifiers with supported punctuation.""" + assert queue_health._repository_name(value) == value + + def test_load_allowlist_accepts_array_and_object_and_rejects_bad_inputs(tmp_path: Path) -> None: """Load both supported allowlist shapes and reject unsafe input files.""" array_path = tmp_path / "array.json" From 2f29c4b30fecc6a00de989f4965cf9ecd382cd3d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 13:03:32 +0900 Subject: [PATCH 3/5] fix(queue-health): validate repository path segments independently --- scripts/ci/actions_queue_health_core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/ci/actions_queue_health_core.py b/scripts/ci/actions_queue_health_core.py index ea90f26135..c21aa05505 100644 --- a/scripts/ci/actions_queue_health_core.py +++ b/scripts/ci/actions_queue_health_core.py @@ -17,7 +17,9 @@ from pathlib import Path from typing import Any -REPOSITORY_PATTERN = re.compile(r"^(?!.*(?:\.\.|\.$))[A-Za-z0-9_.-]+/(?!.*(?:\.\.|\.$))[A-Za-z0-9_.-]+$") +REPOSITORY_PATTERN = re.compile( + r"^(?!.*\.\.)(?![^/]*\./)[A-Za-z0-9_.-]+/(?![^/]*\.$)[A-Za-z0-9_.-]+$" +) QUEUE_STATES = {"QUEUED", "IN_PROGRESS", "PENDING", "REQUESTED"} TERMINAL_STATES = {"COMPLETED"} DEFAULT_QUEUE_AGE_SLO_SECONDS = 900 From e13211f78971cbc59c9450e61bfc1ed766b55deb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 13:04:08 +0900 Subject: [PATCH 4/5] docs(queue-health): record repository identifier boundary evidence --- CHANGELOG.md | 9 +++++++++ docs/product-technical-gap-baseline.md | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d90fa0c899..a89b36df9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### Repository identifiers validate owner and repository segments independently + +- Queue-health repository identifiers now reject a trailing dot in either the + owner or repository segment while preserving valid leading-dot names such as + `.github`. RED commit `c3963dc88` reproduces `owner./repo`; source commit + `2f29c4b30` repairs the segment boundary and adds safe punctuation cases. + The focused regression and `GITHUB_ACTIONS=true` harness pass locally. + Hosted exact-head security Checks and independent review remain required. + ### Intel macOS native archives are bound to x86_64 bytes - The release prescreener now requires every native member in an Intel macOS diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6e5f1c549a..1c7541038b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -5,6 +5,12 @@ 현재 보호된 `main`: `826b92394c63deb6981c3a8d16a724d71f85a0d7` 현재 열린 PR 수: **107** (아래 표에 이 스냅샷의 전체 목록 포함; live API 재수집) +### 2026-10-07 repository identifier trust-boundary delta + +| Gap ID | 상태 | exact-head evidence | causal owner / next gate | +|---|---|---|---| +| CONTROL-QUEUE-REPOSITORY-SEGMENT-01 | **Source repaired on `.github#2595`; hosted exact-head acceptance pending** | Current-head review found that the first negative lookahead inspected the whole `owner/repository` string, so `owner./repo` bypassed the promised owner-segment trailing-dot rejection. RED `c3963dc88` binds that case and valid `.github`/punctuation inputs; GREEN `2f29c4b30` validates owner and repository segments independently. The focused direct regression, byte compilation, and `GITHUB_ACTIONS=true` execution pass locally. | Canonical owner is `scripts/ci/actions_queue_health_core.py` in central `.github`. Fresh hosted security Checks, full-suite evidence, resolved current-head review threads, qualifying independent approval, and ordinary protected merge remain mandatory; no bypass is authorized. | + 이 문서는 제품·기술·운영 Gap을 현재 문서와 현재 GitHub 상태에 묶어 두는 기준선이다. 새 작업은 먼저 이 문서의 Gap ID를 PR 설명과 테스트 증거에 연결하고, PR의 정확한 exact HEAD·Checks·리뷰를 다시 수집한 뒤 구현한다. 표의 상태는 작성 시점의 관측값이므로, 병합 판단에는 재사용하지 않는다. 이 인벤토리는 스냅샷이며 merge authorization이 아니다. ### 2026-09-19 exact-head incident delta From 51aa7c98aae670a7090f3e96e98c547174ac7224 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 7 Oct 2026 04:11:27 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=EB=A6=AC=ED=8F=AC=EC=A7=80=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=9D=B4=EB=A6=84=20=EC=A0=95=EA=B7=9C=EC=8B=9D?= =?UTF-8?q?=EC=9D=98=20=EA=B2=BD=EB=A1=9C=20=EC=A1=B0=EC=9E=91=20=EC=B7=A8?= =?UTF-8?q?=EC=95=BD=EC=A0=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit