1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use anyhow::anyhow;
16 use cmd_runner::{run_cmd_shell, run_cmd_shell_with_color, YellowStderr};
17 use semver::{Version, VersionReq};
18 use std::{env, fs, path::Path};
19 
20 use crate::CargoOptions;
21 
build_boringssl(root: &Path) -> anyhow::Result<()>22 pub fn build_boringssl(root: &Path) -> anyhow::Result<()> {
23     let bindgen_version_req = VersionReq::parse(">=0.69.4")?;
24     let bindgen_version = get_bindgen_version()?;
25 
26     if !bindgen_version_req.matches(&bindgen_version) {
27         return Err(anyhow!("Bindgen does not match expected version: {bindgen_version_req}"));
28     }
29 
30     let vendor_dir = root
31         .parent()
32         .ok_or_else(|| anyhow!("project root dir no parent dir"))?
33         .join("boringssl-build");
34     fs::create_dir_all(&vendor_dir)?;
35 
36     let build_dir = root
37         .parent()
38         .ok_or_else(|| anyhow!("project root dir no parent dir"))?
39         .join("third_party/boringssl/build");
40     fs::create_dir_all(&build_dir)?;
41 
42     let target = run_cmd_shell_with_color::<YellowStderr>(&vendor_dir, "rustc -vV")?
43         .stdout()
44         .lines()
45         .find(|l| l.starts_with("host: "))
46         .and_then(|l| l.split_once(' '))
47         .ok_or_else(|| anyhow!("Couldn't get rustc target"))?
48         .1
49         .to_string();
50     let target = shell_escape::escape(target.into());
51     run_cmd_shell_with_color::<YellowStderr>(
52         &build_dir,
53         format!(
54             "cmake -G Ninja .. -DRUST_BINDINGS={} -DCMAKE_POSITION_INDEPENDENT_CODE=true",
55             target
56         ),
57     )?;
58     run_cmd_shell(&build_dir, "ninja")?;
59 
60     Ok(())
61 }
62 
check_boringssl(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()>63 pub fn check_boringssl(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()> {
64     log::info!("Checking boringssl");
65 
66     build_boringssl(root)?;
67 
68     let bssl_dir = root.join("crypto/crypto_provider_boringssl");
69 
70     let locked_arg = if cargo_options.locked { "--locked" } else { "" };
71 
72     run_cmd_shell(&bssl_dir, format!("cargo check {locked_arg}"))?;
73     run_cmd_shell(&bssl_dir, "cargo fmt --check")?;
74     run_cmd_shell(&bssl_dir, "cargo clippy --all-targets")?;
75     run_cmd_shell(&bssl_dir, cargo_options.test("check_boringssl", ""))?;
76     run_cmd_shell(&bssl_dir, "cargo doc --no-deps")?;
77     run_cmd_shell(
78         root,
79         cargo_options.test(
80             "check_boringssl_ukey2",
81             "-p ukey2_connections -p ukey2_rs --no-default-features --features test_boringssl",
82         ),
83     )?;
84     Ok(())
85 }
86 
87 /// Checks out latest boringssl commit and runs our crypto provider tests against it
check_boringssl_at_head(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()>88 pub fn check_boringssl_at_head(root: &Path, cargo_options: &CargoOptions) -> anyhow::Result<()> {
89     // TODO: find a better way, a kokoro implemented auto-roller?
90     build_boringssl_at_latest(root)?;
91 
92     let bssl_dir = root.join("crypto/crypto_provider_boringssl");
93     run_cmd_shell(&bssl_dir, "cargo check")?;
94     run_cmd_shell(&bssl_dir, cargo_options.test("check_boringssl_latest", ""))?;
95     Ok(())
96 }
97 
build_boringssl_at_latest(root: &Path) -> anyhow::Result<()>98 fn build_boringssl_at_latest(root: &Path) -> anyhow::Result<()> {
99     // Now check boringssl against HEAD. Kokoro does not allow us to directly update the git submodule
100     // so we must use manual hackery instead :/
101     run_cmd_shell(root.parent().unwrap(), "rm -Rf third_party/boringssl")?;
102     run_cmd_shell(
103         &root.parent().unwrap().join("third_party"),
104         "git clone https://boringssl.googlesource.com/boringssl",
105     )?;
106     run_cmd_shell(
107         &root.parent().unwrap().join("third_party/boringssl"),
108         "git checkout origin/master",
109     )?;
110     build_boringssl(root)?;
111     Ok(())
112 }
113 
get_bindgen_version() -> anyhow::Result<Version>114 fn get_bindgen_version() -> anyhow::Result<Version> {
115     let bindgen_version_output = run_cmd_shell(&env::current_dir().unwrap(), "bindgen --version")?;
116 
117     let version = bindgen_version_output
118         .stdout()
119         .lines()
120         .next()
121         .ok_or(anyhow!("bindgen version output stream is empty"))?
122         .strip_prefix("bindgen ")
123         .ok_or(anyhow!("bindgen version output missing expected prefix of \"bindgen \""))?
124         .parse::<Version>()?;
125 
126     Ok(version)
127 }
128