Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
121 changes: 121 additions & 0 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ concurrency:

permissions:
contents: read
pull-requests: read

jobs:
required-workflow-bootstrap:
Expand All @@ -31,6 +32,126 @@ jobs:
echo "Required OpenCode workflow materialized without checking out or
executing pull-request content."

- name: Resolve immutable central policy source
id: trusted_source
env:
JOB_CONTEXT_JSON: ${{ toJSON(job) }}
WORKFLOW_SHA: ${{ github.workflow_sha }}
WORKFLOW_REF: ${{ github.workflow_ref }}
run: |
set -euo pipefail
python3 <<'PY' >>"$GITHUB_OUTPUT"
import json
import os
import re
import sys

try:
job_context = json.loads(os.environ.get("JOB_CONTEXT_JSON") or "{}")
except json.JSONDecodeError as exc:
print(f"::error::Could not parse GitHub workflow context JSON: {exc}", file=sys.stderr)
raise SystemExit(1)

expected_repository = "ContextualWisdomLab/.github"
expected_file = ".github/workflows/opencode-review.yml"
workflow_sha = str(
job_context.get("workflow_sha") or os.environ.get("WORKFLOW_SHA") or ""
).strip()
workflow_ref = str(
job_context.get("workflow_ref") or os.environ.get("WORKFLOW_REF") or ""
).strip()
workflow_ref_head, separator, _ = workflow_ref.partition("@")
if not separator:
print("::error::Required workflow ref is missing its immutable ref separator.", file=sys.stderr)
raise SystemExit(1)
ref_parts = workflow_ref_head.split("/", 2)
if len(ref_parts) < 2 or not ref_parts[0] or not ref_parts[1]:
print("::error::Required workflow ref does not identify a repository.", file=sys.stderr)
raise SystemExit(1)
workflow_repository = "/".join(ref_parts[:2])
workflow_file_path = str(job_context.get("workflow_file_path") or "").strip()
Comment on lines +57 to +72

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: Workflow context resolution relies on env fallback since job context lacks workflow_ keys*

The Resolve immutable central policy source step reads JOB_CONTEXT_JSON = toJSON(job) and then job_context.get("workflow_sha"/"workflow_ref"/"workflow_file_path"). The GitHub job context only exposes status, container, and services, so these .get() calls always return None and the code relies entirely on the WORKFLOW_SHA/WORKFLOW_REF env fallbacks (from github.workflow_sha/github.workflow_ref) and the ref-prefix derivation for workflow_file_path. This is harmless (the fallbacks are correct), but the job_context lookups are effectively dead code — the intent may have been to read a different context (e.g. github).

Open in Devin Review

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


if not workflow_file_path:
prefix = f"{expected_repository}/{expected_file}@"
if workflow_ref.startswith(prefix):
workflow_file_path = expected_file

if workflow_repository != expected_repository:
print(
f"::error::Required workflow repository resolved to {workflow_repository}, expected {expected_repository}.",
file=sys.stderr,
)
raise SystemExit(1)
if not re.fullmatch(r"[0-9a-fA-F]{40}", workflow_sha):
print("::error::Required workflow SHA is missing or malformed.", file=sys.stderr)
raise SystemExit(1)
if workflow_file_path != expected_file:
print("::error::Required workflow file path is missing or unexpected.", file=sys.stderr)
raise SystemExit(1)
expected_ref_prefix = f"{expected_repository}/{expected_file}@"
if not workflow_ref.startswith(expected_ref_prefix):
print("::error::Required workflow ref is missing or inconsistent.", file=sys.stderr)
raise SystemExit(1)
Comment on lines +91 to +94

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.

🔍 workflow_ref prefix match depends on exact org-name casing

The file-path and ref validation build prefix/expected_ref_prefix from the literal expected_repository = "ContextualWisdomLab/.github" and compare with workflow_ref.startswith(prefix) (opencode-review.yml and 85-88). github.workflow_ref reports the repository with its canonical stored casing. If GitHub ever returns a different case than ContextualWisdomLab, the prefix check fails, SystemExit(1) fires, and the step fails on every PR (blocking all PRs). The casing appears consistent with the rest of the repo docs, so this is likely fine, but it is a single point of failure worth confirming against the actual github.workflow_ref value.

Open in Devin Review

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


print(f"repository={workflow_repository}")
print(f"sha={workflow_sha}")
print(f"workflow_file_path={workflow_file_path}")
PY

- name: Materialize trusted central policy source
env:
GH_TOKEN: ${{ github.token }}
TRUSTED_SOURCE_REF: ${{ steps.trusted_source.outputs.sha }}
run: |
set -euo pipefail
if [[ ! "$TRUSTED_SOURCE_REF" =~ ^[0-9a-fA-F]{40}$ ]]; then
echo "::error::Trusted central policy source ref must resolve to the immutable workflow commit SHA before archive materialization."
exit 1
fi
trusted_archive="${RUNNER_TEMP}/trusted-opencode-policy-source.tar.gz"
trusted_source_dir="${GITHUB_WORKSPACE}/.cwl-required-source"
api_url="${GITHUB_API_URL:-https://api.github.com}"
mkdir -p "$trusted_source_dir"
curl -fsSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-o "$trusted_archive" \
"${api_url}/repos/ContextualWisdomLab/.github/tarball/${TRUSTED_SOURCE_REF}"
tar -xzf "$trusted_archive" -C "$trusted_source_dir" --strip-components=1

- name: Verify immutable central policy source
env:
EXPECTED_FILE: ${{ steps.trusted_source.outputs.workflow_file_path }}
run: |
set -euo pipefail
trusted_source_dir="$GITHUB_WORKSPACE/.cwl-required-source"
if [ ! -f "$trusted_source_dir/$EXPECTED_FILE" ] || [ -L "$trusted_source_dir/$EXPECTED_FILE" ]; then
printf '::error::Required workflow source file is missing or symlinked: %s.\n' \
"$EXPECTED_FILE"
exit 1
fi
if [ ! -f "$trusted_source_dir/scripts/ci/pingora_edge_policy.py" ] || [ -L "$trusted_source_dir/scripts/ci/pingora_edge_policy.py" ]; then
echo "::error::Trusted Pingora edge policy helper is missing or symlinked."
exit 1
fi

- name: Enforce Cloudflare Pingora edge policy
if: ${{ github.event_name == 'pull_request_target' }}
env:
GITHUB_TOKEN: ${{ github.token }}
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 }}
EVENT_ACTION: ${{ github.event.action || 'unknown' }}
run: |
set -euo pipefail
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"

Comment thread
seonghobae marked this conversation as resolved.
coverage-source-tree:
name: coverage-source-tree
needs: [required-workflow-bootstrap]
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (
Conflict-scope roots fail closed when the immediate parent directory is a symbolic link.
OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md).
nonnest2 hourly NVIDIA NIM repair is a thin caller at minute 16. See [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md).
Organization edge runtimes use Cloudflare Pingora. Do not add or preserve active Nginx containers, packages, commands, service/config files, or Kubernetes Nginx ingress annotations/classes. Read [`docs/policies/PINGORA_EDGE_POLICY.md`](docs/policies/PINGORA_EDGE_POLICY.md) and ADR-0019 before changing HTTP edge, static-serving, ingress, TLS, or proxy deployment behavior.
The materialization contract is also covered by [`docs/doctoring/exact-artifact-sbom-attestation.md`](docs/doctoring/exact-artifact-sbom-attestation.md).
67 changes: 67 additions & 0 deletions docs/adr/0019-cloudflare-pingora-edge-standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ADR-0019: Standardize the CWL edge runtime on Cloudflare Pingora

- **Status:** Accepted
- **Date:** 2026-08-18
- **Decision owners:** ContextualWisdomLab platform and product maintainers

## Context

CWL repositories currently carry several unrelated Nginx images, configuration
files, ingress annotations, service scripts, and host runbooks. The duplication
creates drift in headers, TLS, timeouts, WebSocket handling, non-root operation,
metrics, and security patching. It also makes every product repository an edge
runtime maintainer.

Cloudflare Pingora supplies an Apache-2.0, Rust-based framework for HTTP/1 and
HTTP/2 proxying, TLS, gRPC/WebSocket forwarding, graceful reload, failover, and
observability. It is a framework, not a drop-in parser for Nginx configuration,
so a governed shared implementation is required.

## Decision

1. Pingora is the only approved CWL public HTTP reverse-proxy, load-balancer, and
static edge runtime.
2. The shared implementation pins Pingora `0.8.1`; updates use a reviewed version
bump, security advisory review, compatibility tests, and exact-current-head CI.
3. Product repositories consume versioned static/proxy artifacts and declarative
contracts. Environment deployment remains in `linux-cluster-ops`.
4. The organization required workflow rejects active Nginx runtime artifacts in
changed final files without executing pull-request code.
5. Initial migration does not use Pingora's experimental cache integration.
6. PHP workloads move to an HTTP application server or reviewed FastCGI adapter
behind Pingora before the public listener changes.

## Consequences

### Positive

- One memory-safe, programmable edge framework and patch stream.
- Reusable security headers, request limits, metrics, graceful shutdown, and
connection-management behavior.
- Product repositories stop maintaining bespoke proxy configuration.
- Exact-head organization enforcement prevents regression.

### Costs and risks

- Nginx configuration cannot be translated mechanically; behavior must be tested.
- The organization owns Rust proxy code and its release lifecycle.
- TLS/SNI, FastCGI, caching, and advanced ingress features need explicit modules.
- A faulty shared artifact has broad blast radius, so canary, digest pinning,
rollback, and independent review are mandatory.

## Alternatives rejected

- **Keep Nginx with templates:** preserves configuration drift and C-runtime risk.
- **Traefik as the universal gateway:** useful off-the-shelf controller, but does
not meet the user-mandated Pingora standard and creates a second edge runtime.
- **Per-repository Pingora binaries:** duplicates security logic and fragments the
upgrade path.
- **Immediate host replacement without behavior tests:** creates unacceptable
outage and certificate risk.

## Validation

The policy scanner has 100% production statement and branch coverage, bounded
GitHub API evidence, path/control escaping, pagination limits, exact-head content
inspection, and fail-closed malformed-evidence tests. Product migrations require
site/proxy behavior tests and deployment-specific smoke tests before cutover.
42 changes: 42 additions & 0 deletions docs/doctoring/pingora-edge-standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Doctoring record: Cloudflare Pingora edge standard

## Decision trace

CWL standardizes public HTTP edge behavior on Cloudflare Pingora and prohibits
active Nginx runtime artifacts. Pingora is treated as a programmable framework;
shared binaries and declarative contracts prevent each product from becoming a
proxy implementation owner.

The minimum allowed Pingora line is `0.8.x`. Versions through `0.7.0` were affected
by a critical HTTP request-smuggling flaw caused by ambiguous HTTP/1 framing;
`0.8.0` patched it. The selected `0.8.1` release additionally bounded default
HTTP/2 server limits and updated security-sensitive Rustls development
dependencies. The initial CWL implementation avoids experimental cache APIs.

## Standards and controls

- HTTP parsing and proxy behavior must follow the patched Pingora framing model
and RFC 9112 semantics referenced by the upstream advisory.
- The shared artifact is Apache-2.0 compatible with CWL permissive-license policy.
- Required-workflow code is bound to its immutable central SHA and never executes
pull-request content.
- Runtime evidence is bounded to one-megabyte UTF-8 regular files and a maximum of
3,000 changed files; missing or malformed evidence fails closed.
- Exact-head product tests cover host/path routing, SPA fallback, security headers,
WebSocket/streaming, body limits, health, metrics, TLS, and graceful shutdown as
applicable.

## APA 7th references

Cloudflare, Inc. (2026, June 4). *Pingora 0.8.1* [Software release]. GitHub.
https://github.com/cloudflare/pingora/releases/tag/0.8.1

Cloudflare, Inc. (2026, March 5). *HTTP request smuggling via HTTP/1.0 and
Transfer-Encoding misparsing* (GHSA-hj7x-879w-vrp7) [Security advisory]. GitHub.
https://github.com/cloudflare/pingora/security/advisories/GHSA-hj7x-879w-vrp7

Cloudflare, Inc. (n.d.). *Pingora* [Computer software]. GitHub. Retrieved August
18, 2026, from https://github.com/cloudflare/pingora

Cloudflare, Inc. (n.d.). *Pingora user guide*. GitHub. Retrieved August 18, 2026,
from https://github.com/cloudflare/pingora/tree/main/docs/user_guide
63 changes: 63 additions & 0 deletions docs/policies/PINGORA_EDGE_POLICY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Cloudflare Pingora Edge Runtime Policy

## Binding rule

ContextualWisdomLab production and test edge runtimes use **Cloudflare Pingora**.
Active Nginx containers, packages, commands, configuration files, Kubernetes
Nginx ingress annotations/classes, and host-service units are prohibited.

This is a runtime boundary, not a vocabulary ban. Documentation, license notices,
source-level scanner tests, and migration histories may name Nginx. Pull requests
that modify a runtime candidate are evaluated against the final exact head file,
so deleting a legacy artifact is allowed while preserving it or introducing a new
one fails closed.

## Why this is not a search-and-replace

Pingora is a programmable Rust framework rather than an Nginx configuration
interpreter. The organization therefore maintains reusable, versioned Pingora
static-serving and proxy artifacts and gives product repositories only declarative
route/site contracts. Product repositories do not fork proxy internals.

## Required migration contract

1. Inventory the current listener, host/path matching, TLS ownership, static root,
upstream protocol, WebSocket/streaming behavior, body/timeout limits, headers,
health probes, metrics, and rollback path.
2. Reproduce those behaviors with the approved Pingora artifact and a versioned
route/site manifest.
3. Add behavior-level tests before deleting the old runtime artifact.
4. Pin Pingora to an exact release at or above `0.8.0`; the shared baseline is
`0.8.1`. Do not use the experimental Pingora cache integration in the initial
migration.
5. Preserve certificate data and rollback evidence, but never keep a runnable
Nginx fallback after cutover. Rollback means redeploying the prior application
release behind Pingora, not reintroducing Nginx.
6. Treat PHP/FastCGI workloads as application-runtime migrations: place an
HTTP-capable PHP application server or a reviewed FastCGI adapter behind
Pingora before cutover. Pingora must remain the public HTTP/TLS edge.

## Ownership

- `.github` owns the binding policy, scanner, shared contracts, and required gate.
- `linux-cluster-ops` owns environment-specific listeners, certificates, routes,
service units, backups, rollout, and host cutover.
- Each product owns its static build or upstream application behavior and tests.
- Keyverse remains the identity authority; an edge runtime never becomes the
identity system of record.

## Enforcement and evidence

The organization-required `required-workflow-bootstrap` job runs trusted
base-branch scanner code at the immutable required-workflow SHA. It reads bounded
changed-file metadata and final UTF-8 content through GitHub's REST API. It does
not check out or execute pull-request content and receives only read permissions.
Malformed, truncated, binary, symlink, oversized, or unavailable evidence fails
closed.

## Exception process

There is no standing Nginx exception. A temporary exception requires a public ADR
with an owner, exact affected asset, buyer impact, security controls, removal date,
and an approved Pingora migration PR. The central scanner remains unchanged; the
exception is implemented by completing the migration before merge.
6 changes: 3 additions & 3 deletions requirements-pip-audit-ci-hashes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ packaging==26.2 \
# via
# pip-audit
# pip-requirements-parser
pip==26.1.2 \
--hash=sha256:382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab \
--hash=sha256:f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605
pip==26.2.1 \
--hash=sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e \
--hash=sha256:f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f
Comment on lines +216 to +218

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.

🔍 Unrelated pip lock bump in an edge-policy PR

requirements-pip-audit-ci-hashes.txt bumps pip 26.1.2 -> 26.2.1, unrelated to the Pingora edge policy. CLAUDE.md requires -hashes.txt files to be regenerated via uv pip compile, never hand-edited. Worth confirming this was a genuine regeneration rather than a manual edge, since no corresponding input change appears in the PR.

Open in Devin Review

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

# via pip-api
pip-api==0.0.34 \
--hash=sha256:8b2d7d7c37f2447373aa2cf8b1f60a2f2b27a84e1e9e0294a3f6ef10eb3ba6bb \
Expand Down
Loading
Loading