Repository: tokio-rs/prost (language: rust)

Issue:
Supply chain security with embedded protoc binaries
We're thinking about using prost over at @MaterializeInc, but the supply chain security of the embedded `protoc` binaries has me very nervous.

Specifically: what sort of validation are you doing before you merge PRs to check that the binaries supplied by third parties are identical to the binaries published by google/protobuf? I did some spot checks and they look identical, but I didn't see anything in your CI pipeline that would assert this. 

We'd honestly probably want to opt out of the bundled protoc deps entirely. I know that's already possible if you specify `PROTOC`, but I'd feel better if there were a way to not even bring the binaries into our dependency tree. Otherwise it seems too easy for accidents to happen; e.g., if that env var somehow gets unset. 

How would y'all feel about adopting an approach similar to rust-protobuf, where the bundled binaries are kept in a separate crate (e.g., `prost-build-vendored`)? Using that crate could be enabled by default, but we could keep it off @MaterializeInc and lint for its absence using `cargo deny`, and I'd sleep a good bit easier at night.

I've also been toying with the idea of building something like `protobuf-src` for Rust (a la `openssl-src`) that builds libprotobuf from source and makes its protoc available to downstream libraries. That could be a nice alternative for `prost-build` to expose. 


Discussion / hints:
Hey @benesch sorry for the delay on this I must have missed it somehow. Are you still interested in getting this working? I think the separate crate idea is good. 

cc @jonhoo I think you've been interested in some of this stuff too.
I think doing something along what's proposed here is a great idea!
No problem, @LucioFranco! Thanks for taking a look now. I actually whipped up a proposal in https://github.com/tokio-rs/prost/pull/576, but we need you or another maintainer to weigh in on how to expose the toggle of which `protoc` to use. The lack of mutually exclusive features in Cargo means there’s no great solution.

I’m also maintaining a fork of prost that _forces_ compiling protoc from source: https://github.com/materializeinc/prost. You could upstream that approach in prost, too! But I figure you probably don’t want to force a C++ dependency on all users of prost. 
By the way, if it’s easiest to sync on Discord or something, happy to find the time!
Yeah, let me try to catch up on everything so may be a bit slow then we can sync. I'd love for yall to not have to maintain a fork so I'd like to get this solved :)
Ok I spent sometime today talking to @jonhoo about this and how we also want to not ship compiled binaries internally here.

I think the proposed solution in #576 is a step in the right direction but I think we will want to avoid having two mutually exclusive feature flags. I think the direction we should head should actually be to not ship any pre-compiled binaries and only allow users to either provide a `protoc` (similar to how we support it now) or to compile it thus requiring users to have a C++ toolchain on hand.

So I think we should follow this sort of flow for obtaining a `protoc`:

- If `PROTOC_NO_VENDOR`
	- excute from `PATH` or fail
- else if `prost-build/vendored` feature is enabled or `protoc` is not found in `PATH`
	- compile `protoc` from source and execute from there
- else
	- excute from `PATH` or fail


I believe this solves most of our issues, while this may increase build times for users that don't have a `protoc` installed on their systems, I do think this will overall improve the security posture of `prost` for all our customers.
> I think the proposed solution in https://github.com/tokio-rs/prost/pull/576 is a step in the right direction but I think we will want to avoid having two mutually exclusive feature flags. I think the direction we should head should actually be to not ship any pre-compiled binaries and only allow users to either provide a protoc (similar to how we support it now) or to compile it thus requiring users to have a C++ toolchain on hand.

This sounds even better than my PR!
@benesch I am working on a PR for this, ill post it in here and tag you on it once its ready. Thanks again for getting this rolling!
Sounds wonderful! You are taking an even stronger stance on this than I had hoped, so I am delighted!

Fix patch:
diff --git a/.github/workflows/continuous-integration-workflow.yaml b/.github/workflows/continuous-integration-workflow.yaml
index 3ba00ac0b..0b8fcca13 100644
--- a/.github/workflows/continuous-integration-workflow.yaml
+++ b/.github/workflows/continuous-integration-workflow.yaml
@@ -8,6 +8,8 @@ jobs:
     steps:
       - name: checkout
         uses: actions/checkout@v2
+        with:
+          submodules: recursive
       - name: install toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -24,7 +26,10 @@ jobs:
   clippy:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          submodules: recursive
       - name: install toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -54,6 +59,8 @@ jobs:
     steps:
       - name: checkout
         uses: actions/checkout@v2
+        with:
+          submodules: recursive
       - name: install toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -78,6 +85,8 @@ jobs:
     steps:
       - name: checkout
         uses: actions/checkout@v2
+        with:
+          submodules: recursive
       - name: install toolchain
         uses: actions-rs/toolchain@v1
         with:
@@ -109,3 +118,20 @@ jobs:
         with:
           command: check
           args: --manifest-path prost-build/Cargo.toml
+
+  vendored:
+    runs-on: ubuntu-latest
+    steps:
+      - name: checkout
+        uses: actions/checkout@v2
+        with:
+          submodules: recursive
+      - name: install toolchain
+        uses: actions-rs/toolchain@v1
+        with:
+            toolchain: stable
+            default: true
+            profile: minimal
+      - name: cargo check
+        run: cd test-vendored && cargo check
+
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..6251abeb8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "prost-build/third-party/protobuf"]
+	path = prost-build/third-party/protobuf
+	url = git@github.com:protocolbuffers/protobuf
diff --git a/Cargo.toml b/Cargo.toml
index a1225ae6b..534046007 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,7 @@ exclude = [
   "fuzz",
   # Same counts for the afl fuzz targets
   "afl",
+  "test-vendored"
 ]
 
 [lib]
diff --git a/README.md b/README.md
index 4d526af29..242092c43 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,13 @@ start-to-finish example.
 `proto3` syntax. `prost`'s goal is to make the generated code as simple as
 possible.
 
+### `protoc`
+
+It's recommended to install `protoc` locally in your path to improve build times.
+Prost uses `protoc` to parse protobuf files and will attempt to compile protobuf
+from source requiring a C++ toolchain. For more info checkout the [`prost-build`](prost-build)
+docs.
+
 ### Packages
 
 Prost can now generate code for `.proto` files that don't have a package spec. 
diff --git a/prost-build/Cargo.toml b/prost-build/Cargo.toml
index c50d487c1..e7415c8b2 100644
--- a/prost-build/Cargo.toml
+++ b/prost-build/Cargo.toml
@@ -12,6 +12,10 @@ readme = "README.md"
 description = "A Protocol Buffers implementation for the Rust Language."
 edition = "2018"
 
+[features]
+default = []
+vendored = []
+
 [dependencies]
 bytes = { version = "1", default-features = false }
 heck = "0.4"
@@ -27,6 +31,8 @@ regex = { version = "1.5.5", default-features = false, features = ["std", "unico
 
 [build-dependencies]
 which = { version = "4", default-features = false }
+cfg-if = "1"
+cmake = "0.1"
 
 [dev-dependencies]
 env_logger = { version = "0.8", default-features = false }
diff --git a/prost-build/README.md b/prost-build/README.md
index e16957c8e..248e0ffdf 100644
--- a/prost-build/README.md
+++ b/prost-build/README.md
@@ -7,6 +7,28 @@
 a Cargo build. See the crate [documentation](https://docs.rs/prost-build/) for examples
 of how to integrate `prost-build` into a Cargo project.
 
+## `protoc`
+
+`prost-build` uses `protoc` to parse the proto files. There are a few ways to make `protoc`
+available for `prost-build`. 
+
+The first option is to include `protoc` in your `PATH` this
+can be done by following the [`protoc` install instructions]. In addition, its possible to
+pass the `PROTOC=<my/path/to/protoc>` environment variable.
+
+[`protoc` install instructions]: https://github.com/protocolbuffers/protobuf#protocol-compiler-installation
+
+The second option is to provide the `vendored` feature flag to `prost-build`. This will
+force `prost-build` to compile `protoc` from the bundled source. This will require that
+you have the correct dependencies installed include a C++ toolchain, cmake, etc. For
+more info on what the required dependencies are check [here].
+
+[here]: https://github.com/protocolbuffers/protobuf/blob/master/src/README.md
+
+If you would like to always ignore vendoring `protoc` you can additionally pass
+`PROTOC_NO_VENDOR` and this will always check the `PATH`/`PROTOC` environment
+variables and never compile `protoc` from source.
+
 ## License
 
 `prost-build` is distributed under the terms of the Apache License (Version 2.0).
diff --git a/prost-build/build.rs b/prost-build/build.rs
index 7f5860f30..89abf0176 100644
--- a/prost-build/build.rs
+++ b/prost-build/build.rs
@@ -1,72 +1,29 @@
 //! Finds the appropriate `protoc` binary and Protobuf include directory for this host, and outputs
 //! build directives so that the main `prost-build` crate can use them.
 //!
-//! The following locations are checked for `protoc` in decreasing priority:
+//! This build script attempts to find `protoc` in a few ways:
 //!
-//!     1. The `PROTOC` environment variable.
-//!     2. The bundled `protoc`.
-//!     3. The `protoc` on the `PATH`.
-//!
-//! If no `protoc` binary is available in these locations, the build fails.
+//!     1. If `PROTOC_NO_VENDOR` is enabled, it will check the `PROTOC` environment variable
+//!         then check the `PATH` for a `protoc` or `protoc.exe`.
+//!     2. If the `vendored` feature flag is enabled or `protoc` can't be found via the environment
+//!         variable or in the `PATH` then `prost-build` will attempt to build `protoc` from the
+//!         bundled source code.
+//!     3. Otherwise, it will attempt to execute from the `PATH` and fail if it does not exist.
 //!
 //! The following locations are checked for the Protobuf include directory in decreasing priority:
 //!
 //!     1. The `PROTOC_INCLUDE` environment variable.
 //!     2. The bundled Protobuf include directory.
+//!
 
+use cfg_if::cfg_if;
 use std::env;
 use std::path::PathBuf;
+use which::which;
 
 /// Returns the path to the location of the bundled Protobuf artifacts.
 fn bundle_path() -> PathBuf {
-    env::current_dir()
-        .unwrap()
-        .join("third-party")
-        .join("protobuf")
-}
-
-/// Returns the path to the `protoc` pointed to by the `PROTOC` environment variable, if it is set.
-fn env_protoc() -> Option<PathBuf> {
-    let protoc = match env::var_os("PROTOC") {
-        Some(path) => PathBuf::from(path),
-        None => return None,
-    };
-
-    Some(protoc)
-}
-
-/// We can only use a bundled protoc if the interpreter necessary to load the binary is available.
-///
-/// The interpreter is specific to the binary and can be queried via e.g. `patchelf
-/// --print-interpreter`, or via readelf, or similar.
-fn is_interpreter(path: &'static str) -> bool {
-    // Here we'd check for it being executable and other things, but for now it being present is
-    // probably good enough.
-    std::fs::metadata(path).is_ok()
-}
-
-/// Returns the path to the bundled `protoc`, if it is available for the host platform.
-fn bundled_protoc() -> Option<PathBuf> {
-    let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
-        ("linux", "x86") if is_interpreter("/lib/ld-linux.so.2") => "protoc-linux-x86_32",
-        ("linux", "x86_64") if is_interpreter("/lib64/ld-linux-x86-64.so.2") => {
-            "protoc-linux-x86_64"
-        }
-        ("linux", "aarch64") if is_interpreter("/lib/ld-linux-aarch64.so.1") => {
-            "protoc-linux-aarch_64"
-        }
-        ("macos", "x86_64") => "protoc-osx-x86_64",
-        ("macos", "aarch64") => "protoc-osx-aarch64",
-        ("windows", _) => "protoc-win32.exe",
-        _ => return None,
-    };
-
-    Some(bundle_path().join(protoc_bin_name))
-}
-
-/// Returns the path to the `protoc` included on the `PATH`, if it exists.
-fn path_protoc() -> Option<PathBuf> {
-    which::which("protoc").ok()
+    env::current_dir().unwrap().join("third-party")
 }
 
 /// Returns the path to the Protobuf include directory pointed to by the `PROTOC_INCLUDE`
@@ -98,14 +55,56 @@ fn bundled_protoc_include() -> PathBuf {
     bundle_path().join("include")
 }
 
+/// Check for `protoc` via the `PROTOC` env var or in the `PATH`.
+fn path_protoc() -> Option<PathBuf> {
+    env::var_os("PROTOC")
+        .map(PathBuf::from)
+        .or_else(|| which("protoc").ok())
+}
+
+/// Returns true if the vendored flag is enabled.
+fn vendored() -> bool {
+    cfg_if! {
+        if #[cfg(feature = "vendored")] {
+            true
+        } else {
+            false
+        }
+    }
+}
+
+/// Compile `protoc` via `cmake`.
+fn compile() -> Option<PathBuf> {
+    let protobuf_src = bundle_path().join("protobuf").join("cmake");
+
+    println!("cargo:rerun-if-changed={}", protobuf_src.display());
+
+    let dst = cmake::Config::new(protobuf_src).build();
+
+    Some(dst.join("bin").join("protoc"))
+}
+
+/// Try to find a `protoc` through a few methods.
+///
+/// Check module docs for more info.
+fn protoc() -> Option<PathBuf> {
+    if env::var_os("PROTOC_NO_VENDOR").is_some() {
+        path_protoc()
+    } else if vendored() {
+        compile()
+    } else {
+        path_protoc().or_else(compile)
+    }
+}
+
 fn main() {
-    let protoc = env_protoc()
-        .or_else(bundled_protoc)
-        .or_else(path_protoc)
-        .expect(
-            "Failed to find the protoc binary. The PROTOC environment variable is not set, \
-             there is no bundled protoc for this platform, and protoc is not in the PATH",
-        );
+    let protoc = protoc().expect(
+        "Failed to find or build the protoc binary. The PROTOC environment \
+    is not set, `protoc` is not in PATH or you are missing the requirements to compile protobuf \
+    from source. \n \
+    Check out the `prost-build` README for instructions on the requirements: \
+    https://github.com/tokio-rs/prost#generated-code",
+    );
 
     let protoc_include = env_protoc_include().unwrap_or_else(bundled_protoc_include);
 
diff --git a/prost-build/src/lib.rs b/prost-build/src/lib.rs
index 5259ea4dd..1ba6f7e0a 100644
--- a/prost-build/src/lib.rs
+++ b/prost-build/src/lib.rs
@@ -97,17 +97,28 @@
 //! PROTOC_INCLUDE=/usr/include
 //! ```
 //!
-//! If `PROTOC` is not found in the environment, then a pre-compiled `protoc` binary bundled in the
-//! prost-build crate is used. Pre-compiled `protoc` binaries exist for Linux (non-musl), macOS,
-//! and Windows systems. If no pre-compiled `protoc` is available for the host platform, then the
-//! `protoc` or `protoc.exe` binary on the `PATH` is used. If `protoc` is not available in any of
-//! these fallback locations, then the build fails.
+//! If no `PROTOC` environment variable is set then `prost-build` will search the
+//! current path for `protoc` or `protoc.exe`. If `protoc` is not found via these
+//! two methods then `prost-build` will attempt to compile `protoc` from the bundled
+//! source.
+//!
+//! If you would not like `prost-build` to not compile `protoc` from source ever then
+//! ensure you have set `PROTO_NO_VENDOR` environment variable as this will disable
+//! compiling from source even if the `vendored` feature flag is enabled.
+//!
+//! If you would like to always compile from source then setting the `vendored` feature
+//! flag will force `prost-build` to always build `protoc` from source.
 //!
 //! If `PROTOC_INCLUDE` is not found in the environment, then the Protobuf include directory
 //! bundled in the prost-build crate is be used.
 //!
-//! To force `prost-build` to use the `protoc` on the `PATH`, add `PROTOC=protoc` to the
-//! environment.
+//! ### Compiling `protoc` from source
+//!
+//! Compiling `protoc` from source requires a few external dependencies. Currently,
+//! `prost-build` uses `cmake` to build `protoc`. For more information check out the
+//! [protobuf build instructions](protobuf-build).
+//!
+//! [protobuf-build]: https://github.com/protocolbuffers/protobuf/blob/master/src/README.md
 
 mod ast;
 mod code_generator;
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/any.proto b/prost-build/third-party/include/google/protobuf/any.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/any.proto
rename to prost-build/third-party/include/google/protobuf/any.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/api.proto b/prost-build/third-party/include/google/protobuf/api.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/api.proto
rename to prost-build/third-party/include/google/protobuf/api.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/compiler/plugin.proto b/prost-build/third-party/include/google/protobuf/compiler/plugin.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/compiler/plugin.proto
rename to prost-build/third-party/include/google/protobuf/compiler/plugin.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/descriptor.proto b/prost-build/third-party/include/google/protobuf/descriptor.proto
similarity index 98%
rename from prost-build/third-party/protobuf/include/google/protobuf/descriptor.proto
rename to prost-build/third-party/include/google/protobuf/descriptor.proto
index 9f0ce6cde..156e410ae 100644
--- a/prost-build/third-party/protobuf/include/google/protobuf/descriptor.proto
+++ b/prost-build/third-party/include/google/protobuf/descriptor.proto
@@ -348,17 +348,17 @@ message FileOptions {
   optional string java_package = 1;
 
 
-  // If set, all the classes from the .proto file are wrapped in a single
-  // outer class with the given name.  This applies to both Proto1
-  // (equivalent to the old "--one_java_file" option) and Proto2 (where
-  // a .proto always translates to a single class, but you may want to
-  // explicitly choose the class name).
+  // Controls the name of the wrapper Java class generated for the .proto file.
+  // That class will always contain the .proto file's getDescriptor() method as
+  // well as any top-level extensions defined in the .proto file.
+  // If java_multiple_files is disabled, then all the other classes from the
+  // .proto file will be nested inside the single wrapper outer class.
   optional string java_outer_classname = 8;
 
-  // If set true, then the Java code generator will generate a separate .java
+  // If enabled, then the Java code generator will generate a separate .java
   // file for each top-level message, enum, and service defined in the .proto
-  // file.  Thus, these types will *not* be nested inside the outer class
-  // named by java_outer_classname.  However, the outer class will still be
+  // file.  Thus, these types will *not* be nested inside the wrapper class
+  // named by java_outer_classname.  However, the wrapper class will still be
   // generated to contain the file's getDescriptor() method as well as any
   // top-level extensions defined in the file.
   optional bool java_multiple_files = 10 [default = false];
@@ -496,6 +496,8 @@ message MessageOptions {
   // this is a formalization for deprecating messages.
   optional bool deprecated = 3 [default = false];
 
+  reserved 4, 5, 6;
+
   // Whether the message is an automatically generated map entry type for the
   // maps field.
   //
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/duration.proto b/prost-build/third-party/include/google/protobuf/duration.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/duration.proto
rename to prost-build/third-party/include/google/protobuf/duration.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/empty.proto b/prost-build/third-party/include/google/protobuf/empty.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/empty.proto
rename to prost-build/third-party/include/google/protobuf/empty.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/field_mask.proto b/prost-build/third-party/include/google/protobuf/field_mask.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/field_mask.proto
rename to prost-build/third-party/include/google/protobuf/field_mask.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/source_context.proto b/prost-build/third-party/include/google/protobuf/source_context.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/source_context.proto
rename to prost-build/third-party/include/google/protobuf/source_context.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/struct.proto b/prost-build/third-party/include/google/protobuf/struct.proto
similarity index 98%
rename from prost-build/third-party/protobuf/include/google/protobuf/struct.proto
rename to prost-build/third-party/include/google/protobuf/struct.proto
index 545215c25..0ac843ca0 100644
--- a/prost-build/third-party/protobuf/include/google/protobuf/struct.proto
+++ b/prost-build/third-party/include/google/protobuf/struct.proto
@@ -55,8 +55,8 @@ message Struct {
 
 // `Value` represents a dynamically typed value which can be either
 // null, a number, a string, a boolean, a recursive struct value, or a
-// list of values. A producer of value is expected to set one of that
-// variants, absence of any variant indicates an error.
+// list of values. A producer of value is expected to set one of these
+// variants. Absence of any variant indicates an error.
 //
 // The JSON representation for `Value` is JSON value.
 message Value {
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/timestamp.proto b/prost-build/third-party/include/google/protobuf/timestamp.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/timestamp.proto
rename to prost-build/third-party/include/google/protobuf/timestamp.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/type.proto b/prost-build/third-party/include/google/protobuf/type.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/type.proto
rename to prost-build/third-party/include/google/protobuf/type.proto
diff --git a/prost-build/third-party/protobuf/include/google/protobuf/wrappers.proto b/prost-build/third-party/include/google/protobuf/wrappers.proto
similarity index 100%
rename from prost-build/third-party/protobuf/include/google/protobuf/wrappers.proto
rename to prost-build/third-party/include/google/protobuf/wrappers.proto
diff --git a/prost-build/third-party/protobuf b/prost-build/third-party/protobuf
new file mode 160000
index 000000000..22d0e265d
--- /dev/null
+++ b/prost-build/third-party/protobuf
@@ -0,0 +1,1 @@
+Subproject commit 22d0e265de7d2b3d2e9a00d071313502e7d4cccf
diff --git a/prost-build/third-party/protobuf/LICENSE b/prost-build/third-party/protobuf/LICENSE
deleted file mode 100644
index 19b305b00..000000000
--- a/prost-build/third-party/protobuf/LICENSE
+++ /dev/null
@@ -1,32 +0,0 @@
-Copyright 2008 Google Inc.  All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-    * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-    * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Code generated by the Protocol Buffer compiler is owned by the owner
-of the input file used when generating it.  This code is not
-standalone and requires a support library to be linked with it.  This
-support library is itself covered by the above license.
diff --git a/prost-build/third-party/protobuf/protoc-linux-aarch_64 b/prost-build/third-party/protobuf/protoc-linux-aarch_64
deleted file mode 100755
index 10e33fcfc..000000000
Binary files a/prost-build/third-party/protobuf/protoc-linux-aarch_64 and /dev/null differ
diff --git a/prost-build/third-party/protobuf/protoc-linux-x86_32 b/prost-build/third-party/protobuf/protoc-linux-x86_32
deleted file mode 100755
index 0f2b633ef..000000000
Binary files a/prost-build/third-party/protobuf/protoc-linux-x86_32 and /dev/null differ
diff --git a/prost-build/third-party/protobuf/protoc-linux-x86_64 b/prost-build/third-party/protobuf/protoc-linux-x86_64
deleted file mode 100755
index e4385d14b..000000000
Binary files a/prost-build/third-party/protobuf/protoc-linux-x86_64 and /dev/null differ
diff --git a/prost-build/third-party/protobuf/protoc-osx-aarch64 b/prost-build/third-party/protobuf/protoc-osx-aarch64
deleted file mode 100755
index e2ba14d7e..000000000
Binary files a/prost-build/third-party/protobuf/protoc-osx-aarch64 and /dev/null differ
diff --git a/prost-build/third-party/protobuf/protoc-osx-x86_64 b/prost-build/third-party/protobuf/protoc-osx-x86_64
deleted file mode 100755
index aacc92892..000000000
Binary files a/prost-build/third-party/protobuf/protoc-osx-x86_64 and /dev/null differ
diff --git a/prost-build/third-party/protobuf/protoc-win32.exe b/prost-build/third-party/protobuf/protoc-win32.exe
deleted file mode 100755
index 9398c1668..000000000
Binary files a/prost-build/third-party/protobuf/protoc-win32.exe and /dev/null differ
diff --git a/prost-build/third-party/update-bundled-protobuf.sh b/prost-build/third-party/update-bundled-protobuf.sh
deleted file mode 100755
index 05655372c..000000000
--- a/prost-build/third-party/update-bundled-protobuf.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-if [ "$#" -ne 1 ]
-then
-  echo "Usage: $0 <protobuf-version>"
-  exit 1
-fi
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-VERSION="$1"
-TEMPDIR=$(mktemp -d "protobuf-$VERSION-XXX")
-ARCHS=( \
-  "linux-aarch_64" \
-  "linux-x86_32" \
-  "linux-x86_64" \
-  "osx-x86_64" \
-  "win32" \
-)
-
-for ARCH in "${ARCHS[@]}"; do
-  mkdir "$TEMPDIR/$ARCH"
-  curl --proto '=https' --tlsv1.2 -sSfL \
-    "https://github.com/protocolbuffers/protobuf/releases/download/v$VERSION/protoc-$VERSION-$ARCH.zip" \
-    -o "$TEMPDIR/$ARCH/protoc.zip"
-
-  EXTENSION=""
-  if [[ "$ARCH" == *"win"* ]]; then
-    EXTENSION=".exe"
-  fi
-
-  unzip "$TEMPDIR/$ARCH/protoc.zip" -d "$TEMPDIR/$ARCH"
-  mv "$TEMPDIR/$ARCH/bin/protoc$EXTENSION" "$DIR/protobuf/protoc-$ARCH$EXTENSION"
-done
-
-
-# Update the include directory
-rm -rf "$DIR/protobuf/include"
-mv "$TEMPDIR/linux-x86_64/include" "$DIR/protobuf/"
-
-# Update the Protocol Buffers license.
-mkdir "$TEMPDIR/src"
-curl --proto '=https' --tlsv1.2 -sSfL \
-  "https://github.com/protocolbuffers/protobuf/archive/v$VERSION.zip" \
-  -o "$TEMPDIR/src/protobuf.zip"
-unzip "$TEMPDIR/src/protobuf.zip" -d "$TEMPDIR/src"
-mv "$TEMPDIR/src/protobuf-$VERSION/LICENSE" "$DIR/protobuf/LICENSE"
-
-rm -rf $TEMPDIR
diff --git a/prost-build/third-party/update-vendored-protobuf.sh b/prost-build/third-party/update-vendored-protobuf.sh
new file mode 100755
index 000000000..d8d741ad5
--- /dev/null
+++ b/prost-build/third-party/update-vendored-protobuf.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -ex
+
+if [ "$#" -ne 1 ]
+then
+  echo "Usage: $0 <protobuf-version>"
+  exit 1
+fi
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+VERSION="$1"
+TEMPDIR=$(mktemp -d "protobuf-$VERSION-XXX")
+ARCH="linux-x86_64"
+
+mkdir "$TEMPDIR/$ARCH"
+curl --proto '=https' --tlsv1.2 -sSfL \
+  "https://github.com/protocolbuffers/protobuf/releases/download/v$VERSION/protoc-$VERSION-$ARCH.zip" \
+  -o "$TEMPDIR/$ARCH/protoc.zip"
+
+unzip "$TEMPDIR/$ARCH/protoc.zip" -d "$TEMPDIR/$ARCH"
+
+# Update the include directory
+rm -rf "$DIR/include"
+mv "$TEMPDIR/linux-x86_64/include" "$DIR/include/"
+
+
+rm -rf $TEMPDIR
+cd "$DIR/protobuf"
+git checkout "v$VERSION"
+cd $DIR
+
+echo "third-party protobuf items updated to v$VERSION"
\ No newline at end of file
diff --git a/prost-types/src/protobuf.rs b/prost-types/src/protobuf.rs
index 1440b4c00..25e82179b 100644
--- a/prost-types/src/protobuf.rs
+++ b/prost-types/src/protobuf.rs
@@ -343,17 +343,17 @@ pub struct FileOptions {
     /// domain names.
     #[prost(string, optional, tag="1")]
     pub java_package: ::core::option::Option<::prost::alloc::string::String>,
-    /// If set, all the classes from the .proto file are wrapped in a single
-    /// outer class with the given name.  This applies to both Proto1
-    /// (equivalent to the old "--one_java_file" option) and Proto2 (where
-    /// a .proto always translates to a single class, but you may want to
-    /// explicitly choose the class name).
+    /// Controls the name of the wrapper Java class generated for the .proto file.
+    /// That class will always contain the .proto file's getDescriptor() method as
+    /// well as any top-level extensions defined in the .proto file.
+    /// If java_multiple_files is disabled, then all the other classes from the
+    /// .proto file will be nested inside the single wrapper outer class.
     #[prost(string, optional, tag="8")]
     pub java_outer_classname: ::core::option::Option<::prost::alloc::string::String>,
-    /// If set true, then the Java code generator will generate a separate .java
+    /// If enabled, then the Java code generator will generate a separate .java
     /// file for each top-level message, enum, and service defined in the .proto
-    /// file.  Thus, these types will *not* be nested inside the outer class
-    /// named by java_outer_classname.  However, the outer class will still be
+    /// file.  Thus, these types will *not* be nested inside the wrapper class
+    /// named by java_outer_classname.  However, the wrapper class will still be
     /// generated to contain the file's getDescriptor() method as well as any
     /// top-level extensions defined in the file.
     #[prost(bool, optional, tag="10", default="false")]
@@ -1681,8 +1681,8 @@ pub struct Struct {
 }
 /// `Value` represents a dynamically typed value which can be either
 /// null, a number, a string, a boolean, a recursive struct value, or a
-/// list of values. A producer of value is expected to set one of that
-/// variants, absence of any variant indicates an error.
+/// list of values. A producer of value is expected to set one of these
+/// variants. Absence of any variant indicates an error.
 ///
 /// The JSON representation for `Value` is JSON value.
 #[derive(Clone, PartialEq, ::prost::Message)]


Test patch:
diff --git a/test-vendored/Cargo.toml b/test-vendored/Cargo.toml
new file mode 100644
index 000000000..0613874f4
--- /dev/null
+++ b/test-vendored/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "test-vendored"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+
+[build-dependencies]
+prost-build = { path = "../prost-build", features = ["vendored"] }
diff --git a/test-vendored/build.rs b/test-vendored/build.rs
new file mode 100644
index 000000000..ada1dc4b2
--- /dev/null
+++ b/test-vendored/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+    prost_build::compile_protos(&["proto/foo.proto"], &["proto"]).unwrap()
+}
diff --git a/test-vendored/proto/foo.proto b/test-vendored/proto/foo.proto
new file mode 100644
index 000000000..40160936b
--- /dev/null
+++ b/test-vendored/proto/foo.proto
@@ -0,0 +1,6 @@
+syntax = "proto3";
+package foo;
+
+message Foo {
+    string bar = 1;
+}
\ No newline at end of file
diff --git a/test-vendored/src/lib.rs b/test-vendored/src/lib.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/test-vendored/src/lib.rs
@@ -0,0 +1,1 @@
+