mirror of
https://github.com/matter-labs/teepot.git
synced 2025-07-20 14:43:56 +02:00
feat: add Google Metadata support and TDX container test
- Introduced `google-metadata` binary for reading GCP instance attributes. - Added TDX container test with new `container-test-tdx` package. - Updated Nix workflow and deployment scripts for Google Metadata integration. - Bumped `anyhow` to 1.0.95 and updated Cargo.lock. Signed-off-by: Harald Hoyer <harald@matterlabs.dev>
This commit is contained in:
parent
e2c31919c9
commit
11a22c9e67
16 changed files with 286 additions and 52 deletions
1
.github/workflows/nix.yml
vendored
1
.github/workflows/nix.yml
vendored
|
@ -73,6 +73,7 @@ jobs:
|
|||
- { nixpackage: 'container-self-attestation-test-sgx-azure' }
|
||||
- { nixpackage: 'container-verify-attestation-sgx' }
|
||||
- { nixpackage: 'container-verify-era-proof-attestation-sgx' }
|
||||
- { nixpackage: 'container-test-tdx' }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
|
|
133
Cargo.lock
generated
133
Cargo.lock
generated
|
@ -337,9 +337,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
|
@ -1927,8 +1927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1999,6 +2001,18 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-metadata"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"reqwest 0.12.9",
|
||||
"reqwest-middleware",
|
||||
"reqwest-retry",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gpt"
|
||||
version = "4.0.0"
|
||||
|
@ -2596,6 +2610,18 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intel-tee-quote-verification-sys"
|
||||
version = "0.2.1"
|
||||
|
@ -3575,6 +3601,17 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
|
@ -3582,7 +3619,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3593,7 +3644,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.5.8",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
@ -3905,7 +3956,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca"
|
|||
dependencies = [
|
||||
"dtoa",
|
||||
"itoa",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"prometheus-client-derive-encode",
|
||||
]
|
||||
|
||||
|
@ -4099,6 +4150,15 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.8"
|
||||
|
@ -4242,6 +4302,52 @@ dependencies = [
|
|||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-middleware"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"http 1.2.0",
|
||||
"reqwest 0.12.9",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-retry"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"futures",
|
||||
"getrandom",
|
||||
"http 1.2.0",
|
||||
"hyper 1.5.2",
|
||||
"parking_lot 0.11.2",
|
||||
"reqwest 0.12.9",
|
||||
"reqwest-middleware",
|
||||
"retry-policies",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "retry-policies"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.3.1"
|
||||
|
@ -5543,7 +5649,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
|
@ -6200,6 +6306,21 @@ version = "0.2.99"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-timer"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"parking_lot 0.11.2",
|
||||
"pin-utils",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.76"
|
||||
|
|
|
@ -42,6 +42,8 @@ pgp = "0.14.2"
|
|||
pkcs8 = { version = "0.10" }
|
||||
rand = "0.8"
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
reqwest-middleware = "0.4.0"
|
||||
reqwest-retry = "0.7.0"
|
||||
rsa = { version = "0.9.6", features = ["sha2", "pem"] }
|
||||
rustls = { version = "0.23.20" }
|
||||
secp256k1 = { version = "0.29", features = ["rand-std", "global-context"] }
|
||||
|
|
4
assets/config.json
Normal file
4
assets/config.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"foo": "bar",
|
||||
"bar": "baz"
|
||||
}
|
|
@ -7,8 +7,12 @@
|
|||
|
||||
set -ex
|
||||
|
||||
BASE_DIR=${0%/*}
|
||||
|
||||
NO=${NO:-1}
|
||||
|
||||
ZONE=${ZONE:-us-central1-c}
|
||||
|
||||
nix build -L .#tdx_google
|
||||
|
||||
gsutil cp result/tdx_base_1.vmdk gs://tdx_vms/
|
||||
|
@ -21,8 +25,8 @@ gcloud migration vms image-imports create \
|
|||
--source-file=gs://tdx_vms/tdx_base_1.vmdk \
|
||||
tdx-img-pre-"${NO}"
|
||||
|
||||
gcloud compute instances stop tdx-pilot --zone us-central1-c --project tdx-pilot || :
|
||||
gcloud compute instances delete tdx-pilot --zone us-central1-c --project tdx-pilot || :
|
||||
gcloud compute instances stop tdx-pilot --zone ${ZONE} --project tdx-pilot || :
|
||||
gcloud compute instances delete tdx-pilot --zone ${ZONE} --project tdx-pilot || :
|
||||
|
||||
while gcloud migration vms image-imports list --location=us-central1 --project=tdx-pilot | grep -F RUNNING; do
|
||||
sleep 1
|
||||
|
@ -36,10 +40,11 @@ gcloud compute images create \
|
|||
tdx-img-f-"${NO}"
|
||||
|
||||
gcloud compute instances create tdx-pilot \
|
||||
--machine-type c3-standard-4 --zone us-central1-c \
|
||||
--machine-type c3-standard-4 --zone ${ZONE} \
|
||||
--confidential-compute-type=TDX \
|
||||
--maintenance-policy=TERMINATE \
|
||||
--image-project=tdx-pilot \
|
||||
--project tdx-pilot \
|
||||
--metadata=container_hub="docker.io",container_image="amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57" \
|
||||
--metadata=container_hub="docker.io",container_image="matterlabsrobot/test-tdx:117p5y281limw0w7b03v802ij00c5gzw" \
|
||||
--metadata-from-file=container_config=$BASE_DIR/config.json \
|
||||
--image tdx-img-f-"${NO}"
|
||||
|
|
16
bin/google-metadata/Cargo.toml
Normal file
16
bin/google-metadata/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "google-metadata"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
reqwest.workspace = true
|
||||
reqwest-middleware.workspace = true
|
||||
reqwest-retry.workspace = true
|
||||
serde_json.workspace = true
|
||||
tokio.workspace = true
|
74
bin/google-metadata/src/main.rs
Normal file
74
bin/google-metadata/src/main.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright (c) 2025 Matter Labs
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use reqwest::Client;
|
||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||
use reqwest_retry::{policies::ExponentialBackoff, Jitter, RetryTransientMiddleware};
|
||||
use serde_json::Value;
|
||||
use std::time::Duration;
|
||||
|
||||
const DEFAULT_INSTANCE_METADATA_BASE_URL: &str =
|
||||
"http://metadata.google.internal/computeMetadata/v1/instance/attributes";
|
||||
|
||||
async fn fetch_gcp_metadata(
|
||||
http_client: &ClientWithMiddleware,
|
||||
metadata_key: &str,
|
||||
) -> Result<Value> {
|
||||
// Validate the metadata key:
|
||||
if metadata_key.is_empty() {
|
||||
bail!("Empty metadata_key");
|
||||
}
|
||||
|
||||
let url = format!("{DEFAULT_INSTANCE_METADATA_BASE_URL}/{metadata_key}");
|
||||
|
||||
// Make an HTTP GET request:
|
||||
let response = http_client
|
||||
.get(url)
|
||||
.header("Metadata-Flavor", "Google")
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
// Handle response:
|
||||
if response.status().is_success() {
|
||||
let metadata_text = response.text().await?;
|
||||
serde_json::from_str(&metadata_text)
|
||||
.map_err(|e| anyhow::format_err!("Failed to parse metadata JSON: {}", e))
|
||||
} else {
|
||||
let status = response.status();
|
||||
let error_body = response
|
||||
.text()
|
||||
.await
|
||||
.unwrap_or_else(|_| "<empty>".to_string());
|
||||
bail!(
|
||||
"Failed to fetch metadata: {}, Response body: {}",
|
||||
status,
|
||||
error_body
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// Build the client with retry middleware and exponential backoff:
|
||||
let retry_policy = ExponentialBackoff::builder()
|
||||
.retry_bounds(Duration::from_secs(1), Duration::from_secs(32))
|
||||
.jitter(Jitter::Bounded)
|
||||
.base(2)
|
||||
.build_with_total_retry_duration(Duration::from_secs(60));
|
||||
let client = ClientBuilder::new(Client::builder().build()?) // Underlying reqwest client
|
||||
.with(RetryTransientMiddleware::new_with_policy(retry_policy)) // Add retry middleware
|
||||
.build();
|
||||
|
||||
// Fetch and display metadata:
|
||||
match fetch_gcp_metadata(&client, "container_config").await {
|
||||
Ok(container_config) => {
|
||||
println!("Container config:\n{:#?}", container_config);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error fetching container config: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
8
checks/cargoClippy/default.nix
Normal file
8
checks/cargoClippy/default.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ teepot }: teepot.teepot.passthru.craneLib.cargoClippy (
|
||||
teepot.teepot.passthru.commonArgs // {
|
||||
pname = "teepot";
|
||||
inherit (teepot.teepot.passthru) cargoArtifacts;
|
||||
}
|
||||
)
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ teepotCrate }: teepotCrate.craneLib.cargoFmt (
|
||||
teepotCrate.commonArgs // {
|
||||
{ teepot }: teepot.teepot.passthru.craneLib.cargoDeny (
|
||||
teepot.teepot.passthru.commonArgs // {
|
||||
pname = "teepot";
|
||||
}
|
||||
)
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ teepotCrate }: teepotCrate.craneLib.cargoDeny (
|
||||
teepotCrate.commonArgs // {
|
||||
{ teepot }: teepot.teepot.passthru.craneLib.cargoFmt (
|
||||
teepot.teepot.passthru.commonArgs // {
|
||||
pname = "teepot";
|
||||
}
|
||||
)
|
18
flake.nix
18
flake.nix
|
@ -25,12 +25,9 @@
|
|||
};
|
||||
|
||||
outputs = inputs:
|
||||
let
|
||||
src = ./.;
|
||||
in
|
||||
inputs.snowfall-lib.mkFlake {
|
||||
inherit inputs;
|
||||
inherit src;
|
||||
src = ./.;
|
||||
|
||||
snowfall.namespace = "teepot";
|
||||
|
||||
|
@ -42,8 +39,6 @@
|
|||
nixsgx-flake.overlays.default
|
||||
vault-auth-tee-flake.overlays.default
|
||||
rust-overlay.overlays.default
|
||||
# somehow the original `src` is not available anymore
|
||||
(final: prev: { teepotCrate = prev.pkgs.callPackage ./teepot-crate.nix { inherit inputs; inherit src; }; })
|
||||
];
|
||||
|
||||
alias = {
|
||||
|
@ -59,16 +54,7 @@
|
|||
};
|
||||
|
||||
outputs-builder = channels: {
|
||||
formatter = channels.nixpkgs.nixpkgs-fmt;
|
||||
|
||||
checks = {
|
||||
inherit
|
||||
(channels.nixpkgs.teepot) cargoFmt;
|
||||
inherit
|
||||
(channels.nixpkgs.teepot) cargoClippy;
|
||||
inherit
|
||||
(channels.nixpkgs.teepot) cargoDeny;
|
||||
};
|
||||
formatter = channels.nixpkgs.nixfmt-rfc-style;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ teepotCrate }: teepotCrate.craneLib.cargoClippy (
|
||||
teepotCrate.commonArgs // {
|
||||
pname = "teepot";
|
||||
inherit (teepotCrate) cargoArtifacts;
|
||||
}
|
||||
)
|
24
packages/container-test-tdx/default.nix
Normal file
24
packages/container-test-tdx/default.nix
Normal file
|
@ -0,0 +1,24 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ dockerTools
|
||||
, buildEnv
|
||||
, teepot
|
||||
}:
|
||||
dockerTools.buildLayeredImage {
|
||||
name = "test-tdx";
|
||||
|
||||
config.Entrypoint = [ "${teepot.teepot.google_metadata}/bin/google-metadata" ];
|
||||
config.Env = [ "LD_LIBRARY_PATH=/lib" ];
|
||||
contents = buildEnv {
|
||||
name = "image-root";
|
||||
|
||||
paths = with dockerTools;[
|
||||
teepot.teepot.google_metadata
|
||||
usrBinEnv
|
||||
binSh
|
||||
caCertificates
|
||||
fakeNss
|
||||
];
|
||||
pathsToLink = [ "/bin" "/lib" "/etc" "/share" ];
|
||||
};
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2024 Matter Labs
|
||||
{ lib, pkgs, makeWrapper, teepotCrate }: teepotCrate.craneLib.buildPackage (
|
||||
{ lib, pkgs, makeWrapper, teepot }:
|
||||
let teepotCrate = teepot.teepotCrate; in
|
||||
teepotCrate.craneLib.buildPackage (
|
||||
teepotCrate.commonArgs // {
|
||||
pname = "teepot";
|
||||
inherit (teepotCrate) cargoArtifacts;
|
||||
|
@ -17,6 +19,7 @@
|
|||
|
||||
outputs = [
|
||||
"out"
|
||||
"google_metadata"
|
||||
"rtmr_calc"
|
||||
"sha384_extend"
|
||||
"tdx_extend"
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
, pkg-config
|
||||
, rust-bin
|
||||
, pkgs
|
||||
, src
|
||||
, openssl
|
||||
}:
|
||||
let
|
||||
rustVersion = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
rustVersion = rust-bin.fromRustupToolchainFile (inputs.src + "/rust-toolchain.toml");
|
||||
rustPlatform = makeRustPlatform {
|
||||
cargo = rustVersion;
|
||||
rustc = rustVersion;
|
||||
|
@ -34,15 +33,15 @@ let
|
|||
strictDeps = true;
|
||||
|
||||
src = with lib.fileset; toSource {
|
||||
root = src;
|
||||
root = inputs.src;
|
||||
fileset = unions [
|
||||
./Cargo.lock
|
||||
./Cargo.toml
|
||||
./bin
|
||||
./crates
|
||||
./rust-toolchain.toml
|
||||
./deny.toml
|
||||
./taplo.toml
|
||||
# Default files from crane (Rust and cargo files)
|
||||
(craneLib.fileset.commonCargoSources inputs.src)
|
||||
(fileFilter (file: file.hasExt "hcl") (inputs.src + "/bin"))
|
||||
# deny.toml and friends
|
||||
(fileFilter (file: file.hasExt "toml") inputs.src)
|
||||
# Custom test data files
|
||||
(maybeMissing (inputs.src + "/crates/teepot/tests/data"))
|
||||
];
|
||||
};
|
||||
|
|
@ -6,10 +6,9 @@
|
|||
, teepot
|
||||
, nixsgx
|
||||
, stdenv
|
||||
, teepotCrate
|
||||
}:
|
||||
let
|
||||
toolchain_with_src = (teepotCrate.rustVersion.override {
|
||||
toolchain_with_src = (teepot.teepot.passthru.rustVersion.override {
|
||||
extensions = [ "rustfmt" "clippy" "rust-src" ];
|
||||
});
|
||||
in
|
||||
|
@ -19,7 +18,7 @@ mkShell {
|
|||
nativeBuildInputs = with pkgs; [
|
||||
toolchain_with_src
|
||||
pkg-config
|
||||
teepotCrate.rustPlatform.bindgenHook
|
||||
teepot.teepot.passthru.rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
packages = with pkgs; [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue