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
13 changes: 12 additions & 1 deletion .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,26 @@ jobs:
TARGET_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.repository }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || 0 }}
PULL_REQUEST_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
# The base branch's tip SHA at event time -- already-reviewed,
# already-merged state. Threaded through so the issue #2193
# research/data artifact path declaration can be resolved only
# from here, never from the untrusted PR head; see
# `evaluate_pull_request`'s `base_ref` parameter.
PULL_REQUEST_BASE_SHA: ${{ github.event.pull_request.base.sha || '' }}
Comment on lines +229 to +234

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Base declarations stay snapshot-bound

The workflow passes the event’s immutable base SHA, not a moving branch name. Queued runs therefore evaluate the declaration from their original reviewed base snapshot.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

EVENT_ACTION: ${{ github.event.action || 'unknown' }}
run: |
set -euo pipefail
base_ref_args=()
if [ -n "$PULL_REQUEST_BASE_SHA" ]; then
base_ref_args=(--base-ref "$PULL_REQUEST_BASE_SHA")
fi
python3 .cwl-required-source/scripts/ci/pingora_edge_policy.py \
--repository "$TARGET_REPOSITORY" \
--pull-request "$PULL_REQUEST_NUMBER" \
--head-sha "$PULL_REQUEST_HEAD_SHA" \
--event-action "$EVENT_ACTION" \
--api-url "https://api.github.com"
--api-url "https://api.github.com" \
"${base_ref_args[@]}"

admit-current-head:
name: admit-current-head
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.d/20260914-pingora-declared-artifact-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Pingora edge policy admits declared research/data artifact paths

- `scripts/ci/pingora_edge_policy.py` previously admitted binary or non-UTF-8 content only by path shape (`DOCUMENTATION_DIRECTORIES` via `_is_known_documentation_path`, plus the `evidence`/`figures` publication directories from #2149), so a research repository's raw data and fitted-model artefacts kept elsewhere by deliberate, owner-approved design -- e.g. `ContextualWisdomLab/late-life-anxiety-reanalysis`'s `local/` and evidence-preservation paths -- were rejected on path shape alone, with no route except relocating them under `docs/` (already done once, for 66 images) or leaving the PR unmergeable. `evaluate_pull_request` now accepts an optional `base_ref` and, when given, resolves a new `.github/edge-policy-artifact-paths.txt` declaration (one relative path prefix per line, no globs, capped at `MAX_DECLARED_ARTIFACT_PREFIXES=64` entries and `MAX_DECLARED_ARTIFACT_PREFIX_DEPTH=8` segments) **only from that base ref, never the pull-request head** -- a PR that adds or widens the declaration gets no benefit from it until that change is itself reviewed and merged, proven by a same-PR self-authorization regression test. The declaration replaces only the path-shape test: `_runtime_path_rule` matches stay rejected inside a declared prefix exactly as inside `docs/` today, and a suffix with no `BINARY_DOCUMENT_MAGIC` entry (most research-data formats have none -- `.xlsx`, `.sav`, `.rds`, `.npz`, …) is admitted only on the stricter "no diff patch + fetched bytes are not valid UTF-8" evidence, so a file that decodes as valid UTF-8 is always still content-scanned, never silently admitted. `.hwpx`/`.pdf`/`.png` under a declared prefix keep the existing structural-evidence checks. A malformed declaration (absolute path, `..`, bare `.`/`/`, a glob character, or over either bound) is a hard `PolicyError` naming the offending entry; a repository with no declaration file at all behaves identically to before this feature existed. `evaluate_pull_request` now also emits a `::notice::` naming the declared prefix and the base ref it came from whenever a declared-prefix admission occurs, so a reviewer can trace it back to the reviewed declaration. `.github/workflows/opencode-review.yml`'s `pull_request_target`-derived `github.event.pull_request.base.sha` is threaded through as `--base-ref` with no new permissions. `tests/test_pingora_edge_policy.py` adds coverage for base-ref admission, the self-authorization refusal, runtime-form and valid-UTF-8 rejection inside a declared prefix, every malformed-declaration shape, and the no-declaration regression guard; `tests/test_pingora_edge_workflow_contract.py` pins the new workflow wiring. `pingora_edge_policy.py` remains 100% branch coverage and 100% `interrogate` docstring coverage. Refs #2193, #2149, #2116.
53 changes: 53 additions & 0 deletions docs/policies/PINGORA_EDGE_POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,59 @@ This is a bounded binary-evidence classifier, not a general image renderer;
visual fidelity and optional ancillary-chunk semantics are outside this gate.
Other binary files remain unavailable evidence and fail closed.

## Declared research/data artifact paths

The scanner's binary exemption is otherwise shaped by path only (`doc`/
`docs`/`documentation`, plus the `evidence`/`figures` publication
directories). A research repository whose raw data and fitted-model
artefacts live elsewhere by deliberate, owner-approved design -- SPSS
`.sav` files, serialized model objects, compressed numeric arrays -- can
opt in without relocating that data under `docs/`.

Add `.github/edge-policy-artifact-paths.txt` at the repository root: one
explicit relative path prefix per non-blank line, no globs or wildcards.
For example:

```
local
evidence/raw
```

**Security property.** `evaluate_pull_request` resolves this file only
from the pull request's *base ref* -- never its head. A pull request that
adds or widens the declaration is not self-authorizing: it gets no benefit
from that change until the change itself is reviewed and merged into the
base branch. This mirrors how the required workflow already treats every
other piece of policy evidence -- current-head content only, no
pull-request-controlled trust.

**What the declaration replaces, and what it does not.** A file under a
declared prefix is admitted on exactly the same evidence documentation
paths already require: `_runtime_path_rule` matches (`Dockerfile`,
`nginx.conf`, service files, and the like) are rejected inside a declared
prefix exactly as inside `docs/` today, and any file that decodes as valid
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.

**Bounds.** The declaration is capped at 64 entries and 8 path segments of
depth per entry (`MAX_DECLARED_ARTIFACT_PREFIXES` /
`MAX_DECLARED_ARTIFACT_PREFIX_DEPTH` in `scripts/ci/pingora_edge_policy.py`)
-- parsing-safety bounds, not a product limit on how many locations a
repository may declare. An absolute path, a `..` traversal component, a
bare `.`/`/`, or a glob character in any entry is a hard `PolicyError`
naming the offending entry; a repository with no declaration file behaves
identically to before this feature existed. When a declared prefix admits a
file, the required workflow logs a `::notice::` naming the prefix and the
base ref the declaration was read from, so a reviewer can trace the
admission back to the reviewed declaration it relied on.

Refs #2193, #2149, #2116.

## Exception process

There is no standing Nginx exception. A temporary exception requires a public ADR
Expand Down
Loading
Loading