Skip to content

fix(pingora): scope Nginx required gate to owned edge-runtime responsibilities #1952

Open

Description

@seonghobae

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:

  1. docs/policies/PINGORA_EDGE_POLICY.md declares 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.
  2. Existing owner handoff [Context Fabric handoff] Admit Pingora edge migrations as versioned EA projections #1608 says static-file Nginx containers such as scopeweave, LineageWeave, and inkspan are 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:

  1. owner RED→GREEN tests for static-only versus actual edge-runtime cases;
  2. docs/policies/PINGORA_EDGE_POLICY.md, ADR 0019, doctoring/TRACEABILITY and .github#1608 to state one consistent bounded-context rule;
  3. required-workflow exact-head tests and full policy coverage GREEN;
  4. 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;
  5. no edits from the pingora-gateway writer to .github source/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

  1. seonghobae commented on Sep 6, 2026

    @seonghobae
    ContributorAuthor

    Single-writer coordination refresh from the Pingora owner lane, 2026-09-07 KST: do not start a competing .github source branch for #1952 while #1946 remains the active writer on the same central policy surface.

    Fresh protected owner state is .github/main@49eb9e7035a6994fffb5b24bf943156be27a02fb via #1979. That protected-main change strengthens tests around cancel-in-progress contracts and is relevant queue/review infrastructure, but it does not satisfy #1952's Nginx/Pingora responsibility-classification defect.

    #1946 remains open at 790ef33ea60ada7d21503ca57ccf955a1a36d44b, changing exactly scripts/ci/pingora_edge_policy.py, tests/test_pingora_edge_policy.py, docs/policies/PINGORA_EDGE_POLICY.md, and CHANGELOG.md. Exact compare against current protected main is diverged: ahead 3 / behind 9, merge base 43024633eba9d96b0456970391360da5a171fbda. 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 .github writer 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 exact 1b6c5307e6ff7837dd7504ea2cc23936ab44a86c. CI 34045381577 is terminal GREEN for OCI runtime, Rust-only load contract and full test/coverage/dependency-lock lanes; Supply Chain 34045381591 is terminal GREEN through exact image, SPDX SBOM, scan and source binding. Exact load artifact 9993754723 proves the unchanged 400-request / 4-VU contract with the bounded Rust origin, zero failed requests and p95 0.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 predecessor ea32917f....

    This progress does not alter .github ownership. No .github source/ref/PR state is modified by this Pingora lane.

  2. seonghobae commented on Sep 8, 2026

    @seonghobae
    ContributorAuthor

    Fresh read-only handoff correction from the Pingora migration lane (2026-09-08): protected .github/main is currently 78a4937c684a54ca8e415822c913742f41c6efc4, not the 43024633... ref named in the issue body. The finding itself still reproduces on that protected head: scripts/ci/pingora_edge_policy.py@78a4937... classifies active FROM/image: nginx..., Nginx runtime paths/commands/packages and ingress-controller markers without a responsibility/profile distinction, while tests/test_pingora_edge_policy.py@78a4937... explicitly expects a changed Dockerfile containing FROM nginx:1.27-alpine to be rejected. Fresh organization inventory still shows static-only Nginx runtime images in scopeweave, LineageWeave, and inkspan, while direct proxy_pass search finds the materially different Naruon reverse-proxy fixture. No .github source/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.

  3. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Fresh Strix security evidence on .github#2106@611ccd73460ab0188e0085956ade6180bb28a91a exposes a separate executable Pingora-policy bypass that belongs in this canonical scanner owner rather than #2106 or DiskSage.

    Artifact: Strix run 34742109546, job 103684345530, strix-reports artifact 10314266999, digest sha256:a05a1bd70db3383ecb0c9d4755e92416bdd3426b7cbe9e632cb7bef6cc69da11. The report contains a CWE-697 / medium finding in scripts/ci/pingora_edge_policy.py.

    The current literal CONTENT_RULES can 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 exercised evaluate_pull_request: these forms yielded zero violations while literal FROM nginx:alpine was 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.

  4. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Fresh security evidence from .github#2106 Required Strix run 34742109546 / job 103684345530 confirms a real bypass in the current protected-main Pingora policy (main@64f483db9d052322c65bcdf1675d66138156f306, scripts/ci/pingora_edge_policy.py blob eb0e3a741a93a89c0364af07ff963920d82f9684). Artifact strix-reports id 10314266999, digest sha256:a05a1bd70db3383ecb0c9d4755e92416bdd3426b7cbe9e632cb7bef6cc69da11 dynamically exercised the actual checker.

    Confirmed RED forms all return zero violations while literal FROM nginx:alpine is correctly rejected:

    • YAML/Compose/Kubernetes quoted image: image: "nginx:1.24", image:'nginx:latest', including no-whitespace form;
    • Dockerfile indirection: FROM ${NGINX_IMAGE};
    • Dockerfile continuation: FROM \\ + newline + nginx:alpine;
    • analogous command/package forms such as systemctl start nginx.service, /usr/sbin/nginx, apt-get install --no-install-recommends nginx, and dnf -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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority: mediumNormal-priority or P2 work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions