diff --git a/CHANGELOG.md b/CHANGELOG.md index 96bf2553aa..c877f93bc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### Pingora declared binary artifacts reject readable runtime directives + +- A file under a base-owned declared research/data prefix no longer gains binary admission merely by adding an invalid UTF-8 byte to readable Nginx runtime content. For suffixes without recognized format magic, the bounded replacement-decoded bytes must also contain no prohibited runtime pattern; `.github#2386` covers `.sh`, `.dat`, and `.txt` names through the production evaluation boundary. ### Queue-health permission contract rejects aggregate token grants - The queue-health workflow contract now pins both workflow-level and collector-job permissions to exactly `contents: read` plus `actions: read`, rejecting scalar `read-all`/`write-all`, quoting/spacing variants, inline maps, and unexpected write scopes. diff --git a/docs/policies/PINGORA_EDGE_POLICY.md b/docs/policies/PINGORA_EDGE_POLICY.md index e7fd78c563..f7a6e6a5ee 100644 --- a/docs/policies/PINGORA_EDGE_POLICY.md +++ b/docs/policies/PINGORA_EDGE_POLICY.md @@ -98,9 +98,11 @@ UTF-8 is still fully content-scanned, never silently admitted. A file whose suffix has a known magic byte (`.hwpx`, `.pdf`, `.png`) is verified by that format's structural evidence; a file with no known magic entry (most research-data formats) is admitted only on the stricter combination of "no -diff patch" and "the fetched bytes are not valid UTF-8" -- a text file can -never be mistaken for a binary artefact merely by sitting under a declared -prefix. +diff patch", "the fetched bytes are not valid UTF-8", and "the +replacement-decoded content contains no prohibited runtime pattern". A text +file cannot be mistaken for a binary artefact merely by sitting under a +declared prefix, and a stray invalid byte cannot hide a readable runtime +directive. **Bounds.** The declaration is capped at 64 entries and 8 path segments of depth per entry (`MAX_DECLARED_ARTIFACT_PREFIXES` / diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e46c8c4788..c33b01f597 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -18,6 +18,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| | CONTROL-OPENCODE-VCS-PYROOT-01 | **Source repaired on `main` (#2123 `ebc69a401`); image-path helper extracted + offline-proven under #2157 follow-up; hosted consumer step-#17 link still required to close the issue** | `ContextualWisdomLab/contextual-orchestrator#1149@684cf28f`의 중앙 [OpenCode run 34701472466](https://github.com/ContextualWisdomLab/.github/actions/runs/34701472466) `coverage-evidence` job `103574547257`은 PR 코드를 실행하기 전에 immutable `ContextualWisdomLab/fast-mlsirm@09f762d`의 `python/fast_mlsirm` import root를 찾지 못해 종료했다. 같은 head의 제품 테스트는 `3602 passed, 2 skipped`, native CodeQL·fuzz·SBOM·SAST·Strix는 성공했다. | `.github`의 `opencode-review-dispatch.yml`이 root/`src/`만 허용한 계약 drift를 소유했다. #2123이 `python/` candidates를 추가해 `main`에 병합했고, #2157 follow-up은 동일 로직을 `scripts/ci/resolve_opencode_base_vcs_import_root.sh`로 추출해 `tests/test_opencode_vcs_python_source_root_contract.py` fixture로 증명한다. Issue #2157 종료는 post-`ebc69a401` consumer `coverage-evidence`가 docker step #17을 통과한 job id를 문서에 링크한 뒤에만 한다. | +| CONTROL-PINGORA-DECLARED-BINARY-RUNTIME-01 | **Source repaired on `.github#2386@dea7532e`; protected integration pending** | A base-owned artifact-prefix declaration admitted a no-patch file after any non-UTF-8 byte, even when readable bytes contained `nginx -c /etc/nginx/nginx.conf`. The production-bound regression covers `.sh`, `.dat`, and `.txt`; the focused suite is the exact-head acceptance target. | `.github` owns `scripts/ci/pingora_edge_policy.py`. Replacement-decoded content must contain no `CONTENT_RULES` match before an unrecognized binary suffix is admitted. Current-head hosted security Checks, qualifying independent approval, ordinary protected merge, and downstream `late-life-anxiety-reanalysis#269` revalidation remain required. | ### 2026-09-27 CodeQL compatibility retirement delta @@ -3437,6 +3438,15 @@ alone -- it is a documented multi-PR hot-file collision zone. Contract: **Evidence / remaining condition.** The standalone fixture mechanism was executed locally against Python stdlib and produced one canonical request followed by terminal HTTP 302 for every hostile target. This is mechanism evidence, not repository acceptance. Final authority requires focused/full exact-tree GREEN, fresh exact-head Security/SAST/Python Security/CodeQL/runtime-quality checks, no unresolved actionable review, ordinary protected-main integration, and downstream consumer validation. No scanner suppression, redirect allowlist widening, provider fallback, workflow gate weakening, or credential-boundary change is included. +## 2026-09-27 Strix AnyIO security-lock carryover + +**Status:** Proposed on `ContextualWisdomLab/.github#2386`; fresh exact-head hosted Checks and qualifying independent approval remain mandatory. + +**Context Map / owner.** The central `.github` security/review bounded context owns the hash-locked Strix CI runtime. PyPI packages and the vulnerability advisory service are upstream evidence; product repositories consume only the released central workflow contract. + +**Gap / RCA.** Exact-head Python Security run [36236245577](https://github.com/ContextualWisdomLab/.github/actions/runs/36236245577), job `108402877544`, found AnyIO `4.14.0` vulnerable to `CVE-2026-63374`, `CVE-2026-64847`, and `CVE-2026-63349`; all three list `4.14.2` as fixed. The generated lock had no explicit AnyIO source constraint, so unrelated PR #2386 inherited a known-vulnerable transitive selection. + +**RED → GREEN / carryover.** RED `761be5b0f63422505b37e28a367a4c5170f302ba` imports #2385's source↔lock contract and fails `1 failed, 1 passed` because the source input lacks `anyio==4.14.2`. GREEN `c59ef9aed32ab4c5138c2b7770ddcc10d7ee8393` adds that exact source constraint; `a895dc5aec775076c3819679eadf0b50a563aa2e` adopts #2385's generated lock blob `eb83beda177c9d2e4ca9b7e2888a1ccb55a123ac`, whose only predecessor differences are version line 143 and hash lines 144–145. Exact remote blobs pass the focused contract `2 passed`. This is complete three-file delta integration, not a claim that #2385 or #2386 is accepted. Completion still requires fresh exact-head pip-audit/other required Checks, no unresolved actionable review, qualifying independent approval, and ordinary protected-main integration. ## 2026-09-27 Git blob protocol-hash SAST authority **Status:** Proposed on `ContextualWisdomLab/.github#2396`; fresh exact-head hosted Checks and qualifying independent approval remain mandatory. diff --git a/scripts/ci/pingora_edge_policy.py b/scripts/ci/pingora_edge_policy.py index 518ef84d3c..0d3a2c0948 100644 --- a/scripts/ci/pingora_edge_policy.py +++ b/scripts/ci/pingora_edge_policy.py @@ -24,14 +24,14 @@ ``.npz``, ...) have no entry in ``BINARY_DOCUMENT_MAGIC``, which only knows ``.hwpx``/``.pdf``/``.png``. Rather than grow that registry for every such format, a file under a declared prefix whose suffix has no magic entry is -admitted on the stricter complement of the UTF-8 decode this module already -performs for every ordinarily-scanned file: no diff patch available, *and* the -fetched bytes fail to decode as UTF-8. That keeps the module's central -guarantee honest -- a file that decodes as valid UTF-8 is never treated as a -binary artifact, since scanning exactly that content is what this module -exists to do -- while still admitting genuinely opaque research binaries -without maintaining an open-ended magic-byte catalog. A suffix that *does* -have a magic entry keeps that entry's existing structural evidence check +admitted only when no diff patch is available, the fetched bytes fail to decode +as UTF-8, and their replacement-decoded text contains no prohibited runtime +pattern. That keeps the module's central guarantee honest -- a file that +decodes as valid UTF-8 is never treated as a binary artifact, and one stray +invalid byte cannot conceal a readable runtime command -- while still +admitting genuinely opaque research binaries without maintaining an open-ended +magic-byte catalog. A suffix that *does* have a magic entry keeps that entry's +existing structural evidence check (``_is_complete_png``, ``_is_complete_hwpx``, or the raw magic-prefix check for ``.pdf``) even under a declared prefix. """ @@ -672,6 +672,8 @@ def _binary_documentation_evidence_confirms( bytes that decode cleanly are never admitted this way, so a valid-UTF-8 file cannot be mistaken for a binary artifact merely by sitting under a declared prefix -- it still reaches the normal content scan instead. + Inspect readable text even when other bytes are invalid UTF-8, so a stray + binary byte cannot conceal an active runtime command. """ try: @@ -687,7 +689,8 @@ def _binary_documentation_evidence_confirms( try: raw.decode("utf-8") except UnicodeDecodeError: - return True + readable = raw.decode("utf-8", errors="replace") + return not any(pattern.search(readable) for _, pattern in CONTENT_RULES) return False return raw.startswith(BINARY_DOCUMENT_MAGIC[suffix]) diff --git a/tests/test_pingora_edge_policy.py b/tests/test_pingora_edge_policy.py index f9bc5888ea..1a428556ad 100644 --- a/tests/test_pingora_edge_policy.py +++ b/tests/test_pingora_edge_policy.py @@ -644,6 +644,36 @@ def opener(url: str, _token: str) -> object: assert [item.rule for item in result] == ["nginx_runtime_path"] +@pytest.mark.parametrize("name", ["deploy.sh", "deploy.dat", "deploy.txt"]) +def test_declared_prefix_does_not_admit_binary_marked_nginx_runtime(name: str) -> None: + """A stray non-UTF-8 byte cannot hide readable runtime commands.""" + + raw = b"#!/bin/sh\nnginx -c /etc/nginx/nginx.conf\n# \xff\n" + + def opener(url: str, _token: str) -> object: + if "/pulls/2197/files" in url: + return [{"filename": f"docs/delivery_interim_20260920/{name}", "status": "added"}] + if _declaration_url_fragment("main") in url: + return encoded_file("docs/delivery_interim_20260920/\n") + assert f"/contents/docs/delivery_interim_20260920/{name}" in url + return { + "type": "file", "encoding": "base64", "size": len(raw), + "content": base64.b64encode(raw).decode("ascii"), + } + + with pytest.raises(policy.PolicyError, match="not valid UTF-8"): + policy.evaluate_pull_request( + api_url="https://api.github.test", + repository="ContextualWisdomLab/example", + pull_request=2197, + head_sha="e" * 40, + event_action="opened", + token="token", + base_ref="main", + opener=opener, + ) + + @pytest.mark.parametrize( ("declaration_text", "message"), [