Repository navigation
fix(pingora): scope Nginx required gate to owned edge-runtime responsibilities #1952
Description
Finding
The current organization-required Pingora gate has a live responsibility-boundary contradiction that can force product-local static serving into the shared edge migration even when no shared Ingress/Edge Routing/TLS/HTTP Policy/Load Balancing responsibility has been established.
Protected .github/main@43024633eba9d96b0456970391360da5a171fbda currently says two incompatible things:
docs/policies/PINGORA_EDGE_POLICY.mddeclares every production/test active Nginx container, package, command, config, ingress class/annotation and host service prohibited, explicitly says the organization maintains reusable Pingora static-serving artifacts, and provides no standing Nginx exception.- Existing owner handoff [Context Fabric handoff] Admit Pingora edge migrations as versioned EA projections #1608 says static-file Nginx containers such as
scopeweave,LineageWeave, andinkspanare not automatically shared-edge migrations merely because they use Nginx; responsibility boundary must be proven before adding them to the queue.
The executable scanner currently implements the broader rule, not the bounded one. Fresh exact-head source is scripts/ci/pingora_edge_policy.py@43024633... (blob 33e58ed87616c71951b74a1da0044b4894bcc756). _needs_content_scan() always scans changed Dockerfile/Containerfile/compose/config candidates and evaluate_pull_request() then loads the final exact-head file content and passes it to scan_content(). Therefore a product that already uses Nginx only as a static-file server can have an otherwise unrelated Dockerfile maintenance PR rejected solely because the unchanged final file still contains FROM nginx....
This is not a request to weaken a public-edge migration gate. It is a DDD/ownership repair: shared Pingora policy should govern actual shared edge-runtime authority, while product static build/serving remains product-owned unless an explicit migration contract promotes that responsibility into the canonical edge bounded context.
RED acceptance
Add owner tests that demonstrate the current false-positive boundary without relying on an exception allowlist by repository name:
- a changed product Dockerfile whose final exact head is a static-only Nginx image (
COPY dist -> /usr/share/nginx/html, no reverse proxy, ingress controller, TLS termination, upstream routing, auth/business policy) must not be classified as a shared-edge migration solely from the image/runtime vocabulary; - a changed Dockerfile/config that carries reverse proxy/upstream routing, Nginx ingress-controller authority, public TLS/HTTP edge policy, or executable Nginx gateway behavior must remain fail-closed until its approved Pingora migration contract exists;
- an existing static runtime must not be able to smuggle
proxy_pass, ingress-controller, TLS-edge, upstream-routing, or other newly edge-owned behavior through the static classification; - policy decisions must be based on an explicit responsibility/profile contract or bounded structural evidence, not per-repository hard-coded exemptions.
Minimal repair direction
Keep .github as the sole owner of the required workflow/scanner, but split the policy conceptually into:
- edge-runtime candidate detection: reverse proxy/upstream routing, ingress controller, public listener/TLS ownership, edge HTTP policy/load balancing or an explicit versioned migration declaration;
- static product-serving/runtime evidence: product-owned static artifact serving that is not automatically promoted into
pingora-gateway.
A versioned owner contract/profile is preferable to heuristics alone. The gate should still fail closed when evidence is incomplete or when a static profile gains edge behavior. Do not solve this by a broad scanner skip, a repository-name allowlist, required-workflow weakening, or retaining runnable Nginx as a rollback mechanism after a real edge cutover.
GREEN / integration evidence
Before closure require:
- owner RED→GREEN tests for static-only versus actual edge-runtime cases;
docs/policies/PINGORA_EDGE_POLICY.md, ADR 0019, doctoring/TRACEABILITY and.github#1608to state one consistent bounded-context rule;- required-workflow exact-head tests and full policy coverage GREEN;
- fresh organization scan showing true reverse-proxy/ingress/TLS edge candidates remain gated while static-only product containers are not automatically queued as shared-edge migrations;
- no edits from the
pingora-gatewaywriter to.githubsource/refs/PR state — this issue is the owner-path handoff only.
Downstream pingora-gateway continues to own reusable Ingress/Edge Routing/TLS/HTTP Policy/Load Balancing/Observability/Admin Config/Runtime Isolation semantics and must not absorb product auth/business/identity authority.
Activity
seonghobae commentedon Sep 6, 2026
Single-writer coordination refresh from the Pingora owner lane, 2026-09-07 KST: do not start a competing
.githubsource branch for #1952 while #1946 remains the active writer on the same central policy surface.Fresh protected owner state is
.github/main@49eb9e7035a6994fffb5b24bf943156be27a02fbvia #1979. That protected-main change strengthens tests aroundcancel-in-progresscontracts and is relevant queue/review infrastructure, but it does not satisfy #1952's Nginx/Pingora responsibility-classification defect.#1946 remains open at
790ef33ea60ada7d21503ca57ccf955a1a36d44b, changing exactlyscripts/ci/pingora_edge_policy.py,tests/test_pingora_edge_policy.py,docs/policies/PINGORA_EDGE_POLICY.md, andCHANGELOG.md. Exact compare against current protected main is diverged: ahead 3 / behind 9, merge base43024633eba9d96b0456970391360da5a171fbda. Treat exact ancestry as authority; point-in-time PR mergeability is not used to decide reconciliation. The repair remains ordinary non-force adoption/reconciliation of intervening protected-main commits, not destructive rebase, force-push, or a parallel replacement branch.The intervening protected-main work is queue/review/Strix/required-workflow contract infrastructure and does not implement the static-only-vs-edge-runtime responsibility contract. #1946 is a distinct oversized Contents/Git-Blobs evidence repair. Preserve its fail-closed oversized-content behavior, reconcile it normally, then have the existing
.githubwriter add #1952's responsibility-profile RED→GREEN on the resulting current owner base.#1952 acceptance remains unchanged: static-only product serving must not be promoted into shared Pingora responsibility merely from Nginx vocabulary, while reverse proxy/upstream routing, ingress-controller, public TLS/HTTP edge policy and explicit edge-runtime contracts remain fail-closed. Do not implement this with repository-name allowlists or broad scanner skips.
Downstream
pingora-gateway#64 is exact1b6c5307e6ff7837dd7504ea2cc23936ab44a86c. CI34045381577is terminal GREEN for OCI runtime, Rust-only load contract and full test/coverage/dependency-lock lanes; Supply Chain34045381591is terminal GREEN through exact image, SPDX SBOM, scan and source binding. Exact load artifact9993754723proves the unchanged 400-request / 4-VU contract with the bounded Rust origin, zero failed requests and p950.9037063 ms. Repeated exact-head CodeRabbit requests on #64 have returned transient errors, so current exact technical-review credit is withheld rather than transferred from predecessorea32917f....This progress does not alter
.githubownership. No.githubsource/ref/PR state is modified by this Pingora lane.seonghobae commentedon Sep 8, 2026
Fresh read-only handoff correction from the Pingora migration lane (2026-09-08): protected
.github/mainis currently78a4937c684a54ca8e415822c913742f41c6efc4, not the43024633...ref named in the issue body. The finding itself still reproduces on that protected head:scripts/ci/pingora_edge_policy.py@78a4937...classifies activeFROM/image: nginx..., Nginx runtime paths/commands/packages and ingress-controller markers without a responsibility/profile distinction, whiletests/test_pingora_edge_policy.py@78a4937...explicitly expects a changed Dockerfile containingFROM nginx:1.27-alpineto be rejected. Fresh organization inventory still shows static-only Nginx runtime images inscopeweave,LineageWeave, andinkspan, while directproxy_passsearch finds the materially different Naruon reverse-proxy fixture. No.githubsource/ref/PR-state was modified by this lane. Please preserve the issue's fail-closed edge behavior while repairing the static-serving/shared-edge bounded-context distinction.seonghobae commentedon Sep 13, 2026
Fresh Strix security evidence on
.github#2106@611ccd73460ab0188e0085956ade6180bb28a91aexposes a separate executable Pingora-policy bypass that belongs in this canonical scanner owner rather than #2106 or DiskSage.Artifact: Strix run
34742109546, job103684345530,strix-reportsartifact10314266999, digestsha256:a05a1bd70db3383ecb0c9d4755e92416bdd3426b7cbe9e632cb7bef6cc69da11. The report contains a CWE-697 / medium finding inscripts/ci/pingora_edge_policy.py.The current literal
CONTENT_RULEScan be bypassed by production-shaped active Nginx forms: quoted Kubernetes/Compose images (image: "nginx:1.24"/'nginx:latest'), no-space quoted image syntax,FROM ${NGINX_IMAGE}, Dockerfile line continuations,systemctl start nginx.service, quoted/usr/sbin/nginx, and package installs with flags. Strix exercisedevaluate_pull_request: these forms yielded zero violations while literalFROM nginx:alpinewas correctly caught.This is not authority to broaden the architectural policy or reject static-only product serving. Keep #1952's bounded-context distinction. Add a realistic RED fixture for active edge-runtime responsibility using quoted/indirect/continued representations, normalize representation before responsibility classification, and keep static-only product evidence non-edge unless the bounded contract proves shared edge authority. Preserve existing true-positive edge cases; do not solve this with repository-name allowlists, broad skips, scanner disablement, or leaf exceptions.
Do not repair this in
.github#2106; protected main already contains the scanner and #2106's effective seven-file delta does not touch it.seonghobae commentedon Sep 13, 2026
Fresh security evidence from
.github#2106Required Strix run34742109546/ job103684345530confirms a real bypass in the current protected-main Pingora policy (main@64f483db9d052322c65bcdf1675d66138156f306,scripts/ci/pingora_edge_policy.pyblobeb0e3a741a93a89c0364af07ff963920d82f9684). Artifactstrix-reportsid10314266999, digestsha256:a05a1bd70db3383ecb0c9d4755e92416bdd3426b7cbe9e632cb7bef6cc69da11dynamically exercised the actual checker.Confirmed RED forms all return zero violations while literal
FROM nginx:alpineis correctly rejected:image: "nginx:1.24",image:'nginx:latest', including no-whitespace form;FROM ${NGINX_IMAGE};FROM \\+ newline +nginx:alpine;systemctl start nginx.service,/usr/sbin/nginx,apt-get install --no-install-recommends nginx, anddnf -y install nginx.This does not resolve the broader DDD question already owned by #1952 about whether static-only product serving belongs in the shared-edge prohibition. The repair must therefore separate syntax normalization/detection correctness from responsibility classification: normalize quoting, continuation, command/package option shapes and safe variable bindings so a representation cannot evade whichever edge-runtime profile is authoritative, while #1952's profile/ownership contract decides whether the detected Nginx use is actually shared-edge authority. Do not broaden the gate by repository-name allowlist or by treating every static image as shared-edge merely to close the security finding.
Acceptance should include RED→GREEN fixtures for the bypass forms plus negative controls, and must preserve fail-closed detection for genuine reverse-proxy/ingress/TLS/upstream-routing behavior. This finding is baseline protected-main security evidence; it is not part of #2106's seven-path semantic delta.