Skip to content

Commit

Permalink
fix(lockfile): compute integrity of packed source (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcjkb authored and vhyrro committed Jan 13, 2025
1 parent ffe71eb commit 28e800e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version = "1.0.0-1"
dependencies = {
"lua >= 5.1",
"pathlib.nvim == 2.2.3",
"rtp.nvim == 1.2.0",
-- "rtp.nvim == 1.2.0",
}

source = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"source": "luarocks_rockspec+https://luarocks.org/",
"hashes": {
"rockspec": "sha256-kdDMqznWlwP9wIqlzPrZ5qEDp6edhlkaasAcQzWTmmM=",
"source": "sha256-arCZdCc4g0VvlQA11V1sHMS7WFSJqfwXC80o0A2igqo="
"source": "sha256-fNO24tL8wApI8j3rk2mdLf5wbbjlUzsvCxki3n0xRw8="
}
},
"d7142f441ca59ebde5927d8a3489966828c6b6655125616485632a1b16362f8e": {
Expand All @@ -24,11 +24,11 @@
"source": "luarocks_rockspec+https://luarocks.org/",
"hashes": {
"rockspec": "sha256-5iL9++6X/JsKKtpIRaRHcnZpn6DrsAQQRWPubZK9erY=",
"source": "sha256-WPVTNoj0POenpqKhTWpyPqLe2+fXxpQC2mTU0NvC8Xw="
"source": "sha256-wbN0gqfxaFgVcFc8EQl2Y8Cccd7jIPtdTMhHRQe5MSU="
}
}
},
"entrypoints": [
"5f37e8dc4251f549b25ec62138484f4912ae3d332e57bdb1b30184db3f59d270"
]
}
}
4 changes: 2 additions & 2 deletions rocks-lib/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ async fn do_build(build: Build<'_>) -> Result<LocalPackage, BuildError> {

let temp_dir = tempdir::TempDir::new(&build.rockspec.package.to_string())?;

operations::FetchSrc::new(
let source_hash = operations::FetchSrc::new(
temp_dir.path(),
build.rockspec,
build.config,
Expand All @@ -253,7 +253,7 @@ async fn do_build(build: Build<'_>) -> Result<LocalPackage, BuildError> {

let hashes = LocalPackageHashes {
rockspec: build.rockspec.hash()?,
source: temp_dir.hash()?,
source: source_hash,
};

if let Some(expected) = &build.rockspec.source.current_platform().integrity {
Expand Down
10 changes: 8 additions & 2 deletions rocks-lib/src/manifest/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use itertools::Itertools;
use mlua::{Lua, LuaSerdeExt};
use reqwest::{header::ToStrError, Client};
use std::time::SystemTime;
use std::time::{Duration, SystemTime};
use std::{cmp::Ordering, collections::HashMap};
use thiserror::Error;
use tokio::{fs, io};
Expand Down Expand Up @@ -90,7 +90,13 @@ async fn manifest_from_server(

// If our cache file does not exist then pull the whole manifest.

let new_manifest = client.get(url).send().await?.text().await?;
let new_manifest = client
.get(url)
.timeout(Duration::from_secs(60 * 10))
.send()
.await?
.text()
.await?;

fs::write(&cache, &new_manifest).await?;

Expand Down
68 changes: 41 additions & 27 deletions rocks-lib/src/operations/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use flate2::read::GzDecoder;
use git2::build::RepoBuilder;
use git2::FetchOptions;
use itertools::Itertools;
use ssri::Integrity;
use std::fs::File;
use std::io;
use std::io::BufReader;
Expand All @@ -14,6 +15,7 @@ use std::path::PathBuf;
use thiserror::Error;

use crate::config::Config;
use crate::hash::HasIntegrity;
use crate::operations;
use crate::package::PackageSpec;
use crate::progress::Progress;
Expand Down Expand Up @@ -42,27 +44,33 @@ impl<State> FetchSrcBuilder<'_, State>
where
State: fetch_src_builder::State + fetch_src_builder::IsComplete,
{
pub async fn fetch(self) -> Result<(), FetchSrcError> {
/// Fetch and unpack the source into the `dest_dir`,
/// returning the source `Integrity`.
pub async fn fetch(self) -> Result<Integrity, FetchSrcError> {
let fetch = self._build();
if let Err(err) = do_fetch_src(&fetch).await {
let package = PackageSpec::new(
fetch.rockspec.package.clone(),
fetch.rockspec.version.clone(),
);
fetch.progress.map(|p| {
p.println(format!(
"⚠️ WARNING: Failed to fetch source for {}: {}",
&package, err
))
});
fetch
.progress
.map(|p| p.println("⚠️ Falling back to .src.rock archive"));
FetchSrcRock::new(&package, fetch.dest_dir, fetch.config, fetch.progress)
.fetch()
.await?;
match do_fetch_src(&fetch).await {
Err(err) => {
let package = PackageSpec::new(
fetch.rockspec.package.clone(),
fetch.rockspec.version.clone(),
);
fetch.progress.map(|p| {
p.println(format!(
"⚠️ WARNING: Failed to fetch source for {}: {}",
&package, err
))
});
fetch
.progress
.map(|p| p.println("⚠️ Falling back to .src.rock archive"));
let integrity =
FetchSrcRock::new(&package, fetch.dest_dir, fetch.config, fetch.progress)
.fetch()
.await?;
Ok(integrity)
}
Ok(integrity) => Ok(integrity),
}
Ok(())
}
}

Expand Down Expand Up @@ -99,7 +107,7 @@ impl<State> FetchSrcRockBuilder<'_, State>
where
State: fetch_src_rock_builder::State + fetch_src_rock_builder::IsComplete,
{
pub async fn fetch(self) -> Result<(), FetchSrcRockError> {
pub async fn fetch(self) -> Result<Integrity, FetchSrcRockError> {
do_fetch_src_rock(self._build()).await
}
}
Expand All @@ -109,14 +117,15 @@ where
pub enum FetchSrcRockError {
DownloadSrcRock(#[from] DownloadSrcRockError),
Unpack(#[from] UnpackError),
Io(#[from] io::Error),
}

async fn do_fetch_src(fetch: &FetchSrc<'_>) -> Result<(), FetchSrcError> {
async fn do_fetch_src(fetch: &FetchSrc<'_>) -> Result<Integrity, FetchSrcError> {
let rockspec = fetch.rockspec;
let rock_source = rockspec.source.current_platform();
let progress = fetch.progress;
let dest_dir = fetch.dest_dir;
match &rock_source.source_spec {
let integrity = match &rock_source.source_spec {
RockSourceSpec::Git(git) => {
let url = &git.url.to_string();
progress.map(|p| p.set_message(format!("🦠 Cloning {}", url)));
Expand All @@ -133,11 +142,13 @@ async fn do_fetch_src(fetch: &FetchSrc<'_>) -> Result<(), FetchSrcError> {
let (object, _) = repo.revparse_ext(commit_hash)?;
repo.checkout_tree(&object, None)?;
}
fetch.dest_dir.hash()?
}
RockSourceSpec::Url(url) => {
progress.map(|p| p.set_message(format!("📥 Downloading {}", url.to_owned())));

let response = reqwest::get(url.to_owned()).await?.bytes().await?;
let hash = response.hash()?;
let file_name = url
.path_segments()
.and_then(|segments| segments.last())
Expand All @@ -159,7 +170,8 @@ async fn do_fetch_src(fetch: &FetchSrc<'_>) -> Result<(), FetchSrcError> {
dest_dir,
progress,
)
.await?
.await?;
hash
}
RockSourceSpec::File(path) => {
if path.is_dir() {
Expand Down Expand Up @@ -195,21 +207,23 @@ async fn do_fetch_src(fetch: &FetchSrc<'_>) -> Result<(), FetchSrcError> {
)
.await?
}
path.hash()?
}
RockSourceSpec::Cvs(_) => unimplemented!(),
RockSourceSpec::Mercurial(_) => unimplemented!(),
RockSourceSpec::Sscm(_) => unimplemented!(),
RockSourceSpec::Svn(_) => unimplemented!(),
}
Ok(())
};
Ok(integrity)
}

async fn do_fetch_src_rock(fetch: FetchSrcRock<'_>) -> Result<(), FetchSrcRockError> {
async fn do_fetch_src_rock(fetch: FetchSrcRock<'_>) -> Result<Integrity, FetchSrcRockError> {
let package = fetch.package;
let dest_dir = fetch.dest_dir;
let config = fetch.config;
let progress = fetch.progress;
let src_rock = operations::download_src_rock(package, config.server(), progress).await?;
let integrity = src_rock.bytes.hash()?;
let cursor = Cursor::new(src_rock.bytes);
let mime_type = infer::get(cursor.get_ref()).map(|file_type| file_type.mime_type());
unpack(
Expand All @@ -221,7 +235,7 @@ async fn do_fetch_src_rock(fetch: FetchSrcRock<'_>) -> Result<(), FetchSrcRockEr
progress,
)
.await?;
Ok(())
Ok(integrity)
}

fn is_single_directory<R: Read + Seek + Send>(reader: R) -> io::Result<bool> {
Expand Down
9 changes: 5 additions & 4 deletions rocks-lib/src/operations/lockfile_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,13 @@ async fn do_add_missing_packages(update: LockfileUpdate<'_>) -> Result<(), Lockf
let rockspec = downloaded_rock.rockspec();
let temp_dir =
tempdir::TempDir::new(&format!("lockfile_update-{}", &rockspec.package))?;
FetchSrc::new(temp_dir.path(), rockspec, &config, &Progress::NoProgress)
.fetch()
.await?;
let source_hash =
FetchSrc::new(temp_dir.path(), rockspec, &config, &Progress::NoProgress)
.fetch()
.await?;
let hashes = LocalPackageHashes {
rockspec: rockspec.hash()?,
source: temp_dir.hash()?,
source: source_hash,
};
let pkg = LocalPackage::from(
&PackageSpec::new(rockspec.package.clone(), rockspec.version.clone()),
Expand Down

0 comments on commit 28e800e

Please sign in to comment.