This is an automated email from the ASF dual-hosted git repository.

viirya pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/spark-connect-gateway.git


The following commit(s) were added to refs/heads/main by this push:
     new 6657bf2  [SPARK-59856] Record the provenance of the vendored Spark 
Connect protos and add a sync script
6657bf2 is described below

commit 6657bf24c6e4b41aaed824ce479e14802b2684bf
Author: Liang-Chi Hsieh <[email protected]>
AuthorDate: Tue Sep 29 11:47:41 2026 -0700

    [SPARK-59856] Record the provenance of the vendored Spark Connect protos 
and add a sync script
    
    ### What changes were proposed in this pull request?
    
    Record where the vendored Spark Connect protocol definitions came from, and 
add a
    script to check or re-sync them.
    
    - **`proto/PROVENANCE.md`** — upstream project and path, the baseline 
revision,
      the licensing position, the two known deltas from upstream, and the 
re-sync
      procedure.
    - **`dev/sync-protos.sh`** — compares `proto/spark/connect/` against
      `apache/spark` and reports drift; overwrites only with `--sync`.
    - **`README.md`** — points at both, and separates *regenerating the 
bindings*
      (already documented) from *updating the `.proto` files themselves* (was 
not).
    
    `proto/spark/connect/` itself is untouched by this PR.
    
    ### Why are the changes needed?
    
    The eleven `.proto` files under `proto/spark/connect/` are copied verbatim 
from
    `apache/spark` and are the gateway's source of protocol truth — 
`crates/genproto`
    generates the Rust bindings from them on every build. Nothing in the repo 
recorded
    where they came from. README called them a "vendored read-only mirror of 
upstream"
    but named no revision, no upstream path, and no way to re-sync.
    
    Three concrete costs:
    
    1. **A release manager has no answer** to "where did these come from, and 
under
       what license" — a question that gets asked during an ASF release vote.
    2. **Nobody can tell how far behind upstream the copy is**, or which 
revision to
       sync from, when Spark Connect's protocol moves.
    3. **"Have these been edited locally since they were copied?"** could only 
be
       answered by archaeology.
    
    Establishing the answer meant comparing all eleven files against upstream 
tags, so
    this records the result rather than leaving it to be redone.
    
    **On the revision.** The copy is from the Spark 4.2 development line, not a
    release: nine of the eleven files are byte-identical to `v4.2.0`, and the 
files
    themselves reference fields "deprecated since Spark 4.2+", but no release 
tag
    matches — `v4.2.0-rc1` through `rc5` were checked too. The doc records 
`v4.2.0` as
    the baseline to diff against and states explicitly that this is *not* a 
claim the
    files were taken from that tag. A version number that looks precise but is 
wrong
    would be worse than recording the uncertainty.
    
    **The comparison surfaced drift that was not previously known.** The 
vendored
    protos are *behind* upstream:
    
    | File | Missing relative to `v4.2.0` |
    |---|---|
    | `relations.proto` | the `NearestByJoin` message and its 
`Relation.rel_type` entry |
    | `pipelines.proto` | the `AutoCdcFlowDetails` message and its 
`expressions.proto` import |
    
    Both are pure upstream additions — nothing was edited locally. This PR 
records
    that and deliberately **does not** fix it: re-syncing moves the wire 
protocol and
    deserves review on its own, not folded into a documentation change.
    
    The drift does not affect the gateway today. `crates/proxy` forwards each 
request
    onward whole and reads only session and identity metadata — nothing there 
inspects
    a plan's `rel_type` or walks the relation tree — so a request carrying one 
of the
    newer messages still routes and forwards correctly. I checked that in the 
code
    rather than assuming it, since it is the reason the drift is not urgent.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. Documentation and a developer script; no protocol, code, or behaviour 
change.
    
    ### How was this patch tested?
    
    **The script was exercised, not just written.** Check mode agrees with the 
manual
    comparison that established the provenance in the first place:
    
    ```
    $ dev/sync-protos.sh
    vendored: proto/spark/connect
    upstream: apache/spark v4.2.0 
sql/connect/common/src/main/protobuf/spark/connect
    
      DIFFERS  pipelines.proto  (+42/-0 lines vs upstream)
      DIFFERS  relations.proto  (+31/-0 lines vs upstream)
    
    identical: 9   differing: 2   only-upstream: 0   only-local: 0
    ```
    
    The `+N/-0` shape is itself the evidence that the drift is one-directional 
— we
    are behind upstream, not forked from it.
    
    `--ref v4.1.3` reports 6 identical / 5 differing, also matching the manual
    comparison, which shows the `--ref` path works rather than the default being
    hardcoded somewhere.
    
    **`--sync` was tested on a throwaway copy of the tree** rather than in 
place,
    since it rewrites protocol files: it took that copy from 9/2 to 11/0, and 
the
    repo's own `proto/` was verified unchanged afterwards.
    
    **Exit codes**: 1 for an unknown ref (with a message naming the ref), 2 for 
an
    unknown argument, 1 for `--ref` with no value, 0 for a clean check. Drift 
itself
    does not fail the check — the point of the default mode is to be runnable 
any time
    to see where things stand.
    
    **Nothing regressed**: `proto/spark/` is unchanged, `cargo build -p 
scg-genproto`
    still compiles the bindings from those files, and the workspace is 204 
passed, 0
    failed, 10 ignored — the same as `main`.
    
    One implementation note for review: the script fetches the upstream 
*directory
    listing* rather than iterating over the local files, so a `.proto` added 
upstream
    is reported as drift instead of being invisible. The reverse case — 
vendored here,
    absent upstream — is reported too.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Yes, co-authored with Claude Code.
    
    Closes #40 from viirya/proto-01-provenance.
    
    Authored-by: Liang-Chi Hsieh <[email protected]>
    Signed-off-by: Liang-Chi Hsieh <[email protected]>
---
 README.md           |  15 +++++-
 dev/sync-protos.sh  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 proto/PROVENANCE.md | 110 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 271 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index ed68108..f789474 100644
--- a/README.md
+++ b/README.md
@@ -414,8 +414,10 @@ crates/
   observability/  # metrics, tracing, admin server
   config/         # YAML config loader
   genproto/       # tonic-generated bindings for spark.connect.*
-proto/spark/connect/
-  *.proto        # vendored read-only mirror of upstream
+proto/
+  PROVENANCE.md  # where the vendored protos came from, and how to re-sync
+  spark/connect/
+    *.proto      # vendored read-only mirror of upstream
 deploy/examples/
   spark-connect-server/  # K8s manifests (apache/spark-kubernetes-operator)
 test/integration/
@@ -434,6 +436,15 @@ cargo build -p scg-genproto
 
 `protoc` must be on `$PATH` (e.g. `brew install protobuf`).
 
+That regenerates the Rust bindings from the `.proto` files already in the tree.
+Updating the `.proto` files themselves against upstream Spark is a separate
+thing — see [proto/PROVENANCE.md](proto/PROVENANCE.md) for which revision they
+correspond to and how they drift, and `dev/sync-protos.sh` to check or re-sync:
+
+```bash
+dev/sync-protos.sh          # report drift against the recorded baseline
+```
+
 ## What ships today
 
 **Proxy core.** Streaming forward of every `SparkConnectService` RPC.
diff --git a/dev/sync-protos.sh b/dev/sync-protos.sh
new file mode 100755
index 0000000..0a487a5
--- /dev/null
+++ b/dev/sync-protos.sh
@@ -0,0 +1,148 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# USAGE-BEGIN
+# Compare the vendored Spark Connect protocol definitions in proto/ against
+# apache/spark, or replace them with a given upstream revision.
+#
+# See proto/PROVENANCE.md for where these files came from and why the default
+# revision below is what it is.
+#
+#   dev/sync-protos.sh                  # report drift against the default ref
+#   dev/sync-protos.sh --ref v4.3.0     # report drift against another ref
+#   dev/sync-protos.sh --sync           # overwrite proto/ from the ref
+#
+# Checking is the default on purpose. Overwriting these files changes the
+# gateway's wire protocol, so it should be a deliberate act reviewed on its own
+# -- not a side effect of running a script to see where things stand.
+# USAGE-END
+
+set -euo pipefail
+
+# The revision proto/PROVENANCE.md records as the comparison baseline. Bump 
this
+# together with that file whenever the vendored protos are re-synced.
+UPSTREAM_REF="v4.2.0"
+
+# Upstream location of the protocol definitions within apache/spark.
+UPSTREAM_DIR="sql/connect/common/src/main/protobuf/spark/connect"
+
+mode="check"
+while [ $# -gt 0 ]; do
+  case "$1" in
+    --sync) mode="sync"; shift ;;
+    --ref) UPSTREAM_REF="${2:?--ref needs a value}"; shift 2 ;;
+    -h|--help)
+      # Print the usage block above rather than keeping a second copy of it:
+      # everything between the markers, with the comment prefix stripped.
+      sed -n '/^# USAGE-BEGIN$/,/^# USAGE-END$/p' "$0" \
+        | grep -v -e '^# USAGE-BEGIN$' -e '^# USAGE-END$' \
+        | sed 's/^# \{0,1\}//'
+      exit 0 ;;
+    *) echo "unknown argument: $1" >&2; exit 2 ;;
+  esac
+done
+
+repo_root=$(cd "$(dirname "$0")/.." && pwd)
+local_dir="$repo_root/proto/spark/connect"
+base_url="https://raw.githubusercontent.com/apache/spark/${UPSTREAM_REF}/${UPSTREAM_DIR}";
+
+tmp=$(mktemp -d)
+trap 'rm -rf "$tmp"' EXIT
+
+echo "vendored: proto/spark/connect"
+echo "upstream: apache/spark ${UPSTREAM_REF} ${UPSTREAM_DIR}"
+echo
+
+# Fetch the upstream file list rather than iterating over what we already have,
+# so that a file added upstream shows up as drift instead of being invisible.
+if ! curl -fsS -m 60 \
+    
"https://api.github.com/repos/apache/spark/contents/${UPSTREAM_DIR}?ref=${UPSTREAM_REF}";
 \
+    > "$tmp/listing.json"; then
+  echo "could not list the upstream directory -- is ${UPSTREAM_REF} a real 
ref?" >&2
+  exit 1
+fi
+
+python3 -c '
+import json, sys
+with open(sys.argv[1]) as fh:
+    entries = json.load(fh)
+if not isinstance(entries, list):
+    sys.exit("unexpected response from the GitHub contents API")
+names = sorted(e["name"] for e in entries
+               if e.get("type") == "file" and e["name"].endswith(".proto"))
+if not names:
+    sys.exit("no .proto files found upstream")
+print("\n".join(names))
+' "$tmp/listing.json" > "$tmp/upstream-names"
+
+same=0
+differ=0
+missing_local=0
+extra_local=0
+
+while read -r name; do
+  [ -n "$name" ] || continue
+  if ! curl -fsS -m 60 -o "$tmp/$name" "$base_url/$name"; then
+    echo "  FETCH-FAILED  $name" >&2
+    exit 1
+  fi
+  if [ ! -f "$local_dir/$name" ]; then
+    echo "  ADDED-UPSTREAM $name  (not vendored here)"
+    missing_local=$((missing_local + 1))
+    [ "$mode" = "sync" ] && cp "$tmp/$name" "$local_dir/$name"
+    continue
+  fi
+  if cmp -s "$local_dir/$name" "$tmp/$name"; then
+    same=$((same + 1))
+  else
+    added=$(diff "$local_dir/$name" "$tmp/$name" | grep -c '^>' || true)
+    removed=$(diff "$local_dir/$name" "$tmp/$name" | grep -c '^<' || true)
+    echo "  DIFFERS  $name  (+${added}/-${removed} lines vs upstream)"
+    differ=$((differ + 1))
+    [ "$mode" = "sync" ] && cp "$tmp/$name" "$local_dir/$name"
+  fi
+done < "$tmp/upstream-names"
+
+# A file we vendor that upstream no longer has is drift too, in the other
+# direction -- most likely a rename or removal we have not picked up.
+for path in "$local_dir"/*.proto; do
+  name=$(basename "$path")
+  if ! grep -qxF "$name" "$tmp/upstream-names"; then
+    echo "  NOT-UPSTREAM  $name  (vendored here, absent from ${UPSTREAM_REF})"
+    extra_local=$((extra_local + 1))
+  fi
+done
+
+echo
+echo "identical: ${same}   differing: ${differ}   only-upstream: 
${missing_local}   only-local: ${extra_local}"
+
+if [ "$mode" = "sync" ]; then
+  echo
+  echo "proto/ now matches ${UPSTREAM_REF}. Next:"
+  echo "  1. cargo build -p scg-genproto    # the bindings are generated, not 
committed"
+  echo "  2. cargo test --workspace"
+  echo "  3. update the revision in proto/PROVENANCE.md and UPSTREAM_REF above"
+  exit 0
+fi
+
+# Drift is the normal state between syncs, so report it without failing; the
+# whole point of the check mode is to be runnable at any time to see where the
+# vendored copy stands.
+if [ $((differ + missing_local + extra_local)) -gt 0 ]; then
+  echo "proto/ has drifted from ${UPSTREAM_REF}; see proto/PROVENANCE.md."
+  echo "Re-sync with: dev/sync-protos.sh --sync --ref ${UPSTREAM_REF}"
+fi
diff --git a/proto/PROVENANCE.md b/proto/PROVENANCE.md
new file mode 100644
index 0000000..7b8038d
--- /dev/null
+++ b/proto/PROVENANCE.md
@@ -0,0 +1,110 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Provenance of the vendored Spark Connect protocol definitions
+
+The eleven `.proto` files under `spark/connect/` are **copied verbatim from
+[apache/spark](https://github.com/apache/spark)**. They are not written or
+maintained here, and they are not generated: they are checked-in schema source.
+
+| | |
+|---|---|
+| Upstream project | `apache/spark` |
+| Upstream path | `sql/connect/common/src/main/protobuf/spark/connect/` |
+| Baseline revision | `v4.2.0` (see *Which revision* below) |
+| Files vendored | all 11 `.proto` files in that directory |
+| License | Apache-2.0 — the same license as this project; each file keeps its 
ASF header |
+
+The Rust bindings are generated from these files at build time by
+`crates/genproto/build.rs` (via `tonic-prost-build`) into `target/`, so no
+generated code is committed. `crates/genproto/build.rs` reads every `.proto` in
+the directory and fails if it is empty.
+
+## Which revision
+
+The vendored copy predates the `v4.2.0` release. It matches `v4.2.0` exactly 
for
+9 of the 11 files, and the files themselves refer to fields "deprecated since
+Spark 4.2+", so it was taken from the Spark 4.2 development line — but from an
+untagged commit, not from a release. No `v4.2.0-rcN` tag matches either.
+
+`v4.2.0` is recorded as the baseline revision because it is the earliest
+*released* tag the vendored copy is consistent with, which makes it a 
meaningful
+thing to diff against. It is not a claim that these files were taken from that
+tag.
+
+Two files differ from `v4.2.0`, in both cases because upstream has content the
+vendored copy does not:
+
+| File | Missing relative to `v4.2.0` |
+|---|---|
+| `spark/connect/relations.proto` | the `NearestByJoin` message and its 
`Relation.rel_type` entry |
+| `spark/connect/pipelines.proto` | the `AutoCdcFlowDetails` message and its 
`import "spark/connect/expressions.proto"` |
+
+Both are pure additions upstream: nothing in the vendored files was edited
+locally. In other words the vendored protos are slightly **behind** upstream, 
not
+forked from it.
+
+This does not currently affect the gateway. It forwards each
+`SparkConnectService` request onward as a whole and only ever reads the
+session and identity metadata — nothing in `crates/proxy` inspects a plan's
+`rel_type` or walks the relation tree. So a request carrying one of these newer
+messages is still routed and forwarded correctly.
+
+What the gap does mean is that anything which needs to *inspect* one of those
+newer messages — a routing rule keyed on plan shape, say — would have to 
re-sync
+first.
+
+## Checking and re-syncing
+
+`dev/sync-protos.sh` compares the vendored files against upstream and reports
+drift:
+
+```bash
+dev/sync-protos.sh                   # against the recorded baseline (v4.2.0)
+dev/sync-protos.sh --ref v4.3.0      # against some other upstream ref
+```
+
+It lists the upstream directory rather than iterating over the local files, so 
a
+file **added** upstream is reported as drift instead of being silently missed. 
A
+file vendored here but absent upstream is reported too.
+
+Re-syncing is a separate, deliberate step:
+
+```bash
+dev/sync-protos.sh --sync --ref v4.2.0
+```
+
+Checking is the default because overwriting these files changes the protocol 
the
+gateway speaks. After a `--sync`:
+
+1. `cargo build -p scg-genproto` — regenerate the bindings and confirm they 
compile.
+2. `cargo test --workspace` — the proxy's routing and session handling assume 
the
+   message shapes.
+3. Update the **baseline revision** in the table above and `UPSTREAM_REF` in
+   `dev/sync-protos.sh` so they keep agreeing with each other.
+
+A re-sync is worth reviewing on its own rather than folding into an unrelated
+change, since it moves the wire protocol.
+
+## For a release
+
+These files are third-party content redistributed in the source release. They
+are Apache-2.0 licensed and retain their upstream ASF headers, so they need no
+separate entry in `LICENSE`, but the source release's `NOTICE`-side paperwork
+should account for them as sourced from `apache/spark`. That belongs with the
+`LICENSE-binary` / `NOTICE-binary` dependency-census work, which is still
+outstanding.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to