Skip to content

Commit

Permalink
Merge pull request #1497 from axodotdev/use-checksum-in-installers
Browse files Browse the repository at this point in the history
Verify checksums in `install.sh`
  • Loading branch information
fasterthanlime authored Nov 6, 2024
2 parents f1b4789 + 34ce732 commit 7156093
Show file tree
Hide file tree
Showing 67 changed files with 4,323 additions and 239 deletions.
37 changes: 27 additions & 10 deletions cargo-dist-schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ pub type LocalPath = String;
///
/// (Should we normalize this one?)
pub type RelPath = String;
/// The unique ID of an Artifact
pub type ArtifactId = String;

declare_strongly_typed_string! {
/// The unique ID of an Artifact
pub struct ArtifactId => &ArtifactIdRef;
}

/// The unique ID of a System
pub type SystemId = String;
/// The unique ID of an Asset
Expand Down Expand Up @@ -403,6 +407,19 @@ pub struct Release {
pub hosting: Hosting,
}

declare_strongly_typed_string! {
/// A lowercase descriptor for a checksum algorithm, like "sha256"
/// or "blake2b".
///
/// TODO(amos): Honestly this type should not exist, it's just what
/// `ChecksumStyle` serializes to. `ChecksumsStyle` should just
/// be serializable, that's it.
pub struct ChecksumExtension => &ChecksumExtensionRef;

/// A checksum value, usually the lower-cased hex string of the checksum
pub struct ChecksumValue => &ChecksumValueRef;
}

/// A distributable artifact that's part of a Release
///
/// i.e. a zip or installer
Expand All @@ -415,7 +432,7 @@ pub struct Artifact {
/// indicate you can install the application with `cargo install` or `npm install`.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub name: Option<String>,
pub name: Option<ArtifactId>,
/// The kind of artifact this is (e.g. "executable-zip")
#[serde(flatten)]
pub kind: ArtifactKind,
Expand All @@ -442,14 +459,14 @@ pub struct Artifact {
/// id of an Artifact that contains the checksum for this Artifact
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub checksum: Option<String>,
pub checksum: Option<ArtifactId>,
/// checksums for this artifact
///
/// keys are the name of an algorithm like "sha256" or "sha512"
/// values are the actual hex string of the checksum
#[serde(default)]
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub checksums: BTreeMap<String, String>,
pub checksums: BTreeMap<ChecksumExtension, ChecksumValue>,
}

/// An asset contained in an artifact (executable, license, etc.)
Expand Down Expand Up @@ -546,7 +563,7 @@ pub struct ExecutableAsset {
/// The name of the Artifact containing symbols for this executable
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub symbols_artifact: Option<String>,
pub symbols_artifact: Option<ArtifactId>,
}

/// A C dynamic library artifact (so/dylib/dll)
Expand All @@ -555,7 +572,7 @@ pub struct DynamicLibraryAsset {
/// The name of the Artifact containing symbols for this library
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub symbols_artifact: Option<String>,
pub symbols_artifact: Option<ArtifactId>,
}

/// A C static library artifact (a/lib)
Expand All @@ -564,7 +581,7 @@ pub struct StaticLibraryAsset {
/// The name of the Artifact containing symbols for this library
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub symbols_artifact: Option<String>,
pub symbols_artifact: Option<ArtifactId>,
}

/// Info about a manifest version
Expand Down Expand Up @@ -612,7 +629,7 @@ impl Format {

impl DistManifest {
/// Create a new DistManifest
pub fn new(releases: Vec<Release>, artifacts: BTreeMap<String, Artifact>) -> Self {
pub fn new(releases: Vec<Release>, artifacts: BTreeMap<ArtifactId, Artifact>) -> Self {
Self {
dist_version: None,
announcement_tag: None,
Expand Down Expand Up @@ -655,7 +672,7 @@ impl DistManifest {
pub fn artifacts_for_release<'a>(
&'a self,
release: &'a Release,
) -> impl Iterator<Item = (&'a str, &'a Artifact)> {
) -> impl Iterator<Item = (&'a ArtifactIdRef, &'a Artifact)> {
release
.artifacts
.iter()
Expand Down
4 changes: 2 additions & 2 deletions cargo-dist/src/backend/installer/homebrew.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Code for generating formula.rb

use axoasset::LocalAsset;
use cargo_dist_schema::DistManifest;
use cargo_dist_schema::{ChecksumValue, DistManifest};
use serde::Serialize;
use spdx::{
expression::{ExprNode, Operator},
Expand Down Expand Up @@ -119,7 +119,7 @@ struct HomebrewFragment {
/// SHA256 sum of the fragment. When building "just the installers", like
/// when running `dist build --artifacts global` locally, we don't have
/// the SHA256 for the fragment, since we didn't actually build them.
sha256: Option<String>,
sha256: Option<ChecksumValue>,

/// homebrew package dependencies
dependencies: Vec<String>,
Expand Down
8 changes: 4 additions & 4 deletions cargo-dist/src/backend/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::collections::BTreeMap;

use camino::Utf8PathBuf;
use cargo_dist_schema::{EnvironmentVariables, Hosting, TargetTriple};
use cargo_dist_schema::{ArtifactId, EnvironmentVariables, Hosting, TargetTriple};
use homebrew::HomebrewFragments;
use macpkg::PkgInstallerInfo;
use serde::Serialize;
Expand Down Expand Up @@ -99,7 +99,7 @@ pub struct InstallerInfo {
#[derive(Debug, Clone, Serialize)]
pub struct ExecutableZipFragment {
/// The id of the artifact
pub id: String,
pub id: ArtifactId,
/// The target the artifact supports
pub target_triple: TargetTriple,
/// The executables the artifact contains (name, assumed at root)
Expand All @@ -120,7 +120,7 @@ pub struct ExecutableZipFragment {
#[derive(Debug, Clone, Serialize)]
pub struct UpdaterFragment {
/// The id of the artifact
pub id: String,
pub id: ArtifactId,
/// The binary the artifact contains (name, assumed at root)
pub binary: String,
pub binary: ArtifactId,
}
4 changes: 2 additions & 2 deletions cargo-dist/src/backend/installer/npm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use axoasset::{LocalAsset, SourceFile};
use camino::{Utf8Path, Utf8PathBuf};
use cargo_dist_schema::{GlibcVersion, TargetTriple};
use cargo_dist_schema::{ArtifactId, GlibcVersion, TargetTriple};
use serde::Serialize;

use super::InstallerInfo;
Expand Down Expand Up @@ -46,7 +46,7 @@ type PackageJsonPlatforms = SortedMap<TargetTriple, PackageJsonPlatform>;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct PackageJsonPlatform {
artifact_name: String,
artifact_name: ArtifactId,
bins: SortedMap<String, String>,
zip_ext: String,
}
Expand Down
17 changes: 15 additions & 2 deletions cargo-dist/src/backend/installer/shell.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
//! Code for generating installer.sh

use axoasset::LocalAsset;
use cargo_dist_schema::DistManifest;

use crate::{backend::templates::TEMPLATE_INSTALLER_SH, errors::DistResult, DistGraph};

use super::InstallerInfo;

pub(crate) fn write_install_sh_script(dist: &DistGraph, info: &InstallerInfo) -> DistResult<()> {
pub(crate) fn write_install_sh_script(
dist: &DistGraph,
info: &InstallerInfo,
manifest: &DistManifest,
) -> DistResult<()> {
let mut info = info.clone();
info.platform_support = Some(dist.release(info.release).platform_support.clone());
let platform_support = dist.release(info.release).platform_support.clone();

info.platform_support = Some(if dist.local_builds_are_lies {
// if local builds are lies, the artifacts that are "fake-built" have a different
// checksum every time, so we can't use those in the generated installer
platform_support
} else {
platform_support.with_checksums_from_manifest(manifest)
});

let script = dist
.templates
Expand Down
8 changes: 4 additions & 4 deletions cargo-dist/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::BTreeMap;
use axoasset::{toml_edit, SourceFile};
use axoproject::local_repo::LocalRepo;
use camino::{Utf8Path, Utf8PathBuf};
use cargo_dist_schema::{TargetTriple, TargetTripleRef};
use cargo_dist_schema::{ChecksumExtensionRef, TargetTriple, TargetTripleRef};
use serde::{Deserialize, Serialize};

use crate::announce::TagSettings;
Expand Down Expand Up @@ -662,16 +662,16 @@ pub enum ChecksumStyle {

impl ChecksumStyle {
/// Get the extension of a checksum
pub fn ext(self) -> &'static str {
match self {
pub fn ext(self) -> &'static ChecksumExtensionRef {
ChecksumExtensionRef::from_str(match self {
ChecksumStyle::Sha256 => "sha256",
ChecksumStyle::Sha512 => "sha512",
ChecksumStyle::Sha3_256 => "sha3-256",
ChecksumStyle::Sha3_512 => "sha3-512",
ChecksumStyle::Blake2s => "blake2s",
ChecksumStyle::Blake2b => "blake2b",
ChecksumStyle::False => "false",
}
})
}
}

Expand Down
6 changes: 3 additions & 3 deletions cargo-dist/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use axoproject::errors::AxoprojectError;
use backtrace::Backtrace;
use camino::Utf8PathBuf;
use cargo_dist_schema::TargetTriple;
use cargo_dist_schema::{ArtifactId, TargetTriple};
use color_backtrace::BacktracePrinter;
use console::style;
use miette::{Diagnostic, SourceOffset, SourceSpan};
Expand Down Expand Up @@ -264,7 +264,7 @@ pub enum DistError {
#[diagnostic(help("depends on {spec1} and {spec2}"))]
MultiPackage {
/// Name of the artifact
artifact_name: String,
artifact_name: ArtifactId,
/// One of the packages
spec1: String,
/// A different package
Expand All @@ -276,7 +276,7 @@ pub enum DistError {
#[diagnostic(help("This should be impossible, you did nothing wrong, please file an issue!"))]
NoPackage {
/// Name of the msi
artifact_name: String,
artifact_name: ArtifactId,
},

/// These GUIDs for msi's are required and enforced by `dist generate --check`
Expand Down
8 changes: 5 additions & 3 deletions cargo-dist/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
DistError, DistGraph, DistGraphBuilder, HostingInfo,
};
use axoproject::WorkspaceGraph;
use cargo_dist_schema::{DistManifest, Hosting};
use cargo_dist_schema::{ArtifactIdRef, DistManifest, Hosting};
use gazenot::{AnnouncementKey, Gazenot};

/// Do hosting
Expand Down Expand Up @@ -212,6 +212,8 @@ fn check_hosting(_dist: &DistGraph, _manifest: &DistManifest, _abyss: &Gazenot)
}

fn upload_to_hosting(dist: &DistGraph, manifest: &DistManifest, abyss: &Gazenot) -> DistResult<()> {
const DIST_MANIFEST_ARTIFACT_ID: &ArtifactIdRef = ArtifactIdRef::from_str("dist-manifest.json");

// Gather up the files to upload for each release
let files = manifest.releases.iter().filter_map(|release| {
// Github Releases only has semantics on Announce
Expand All @@ -224,8 +226,8 @@ fn upload_to_hosting(dist: &DistGraph, manifest: &DistManifest, abyss: &Gazenot)
let files = manifest
.artifacts_for_release(release)
.filter_map(|(_id, artifact)| artifact.name.as_deref())
.chain(Some("dist-manifest.json"))
.map(|name| dist.dist_dir.join(name))
.chain(Some(DIST_MANIFEST_ARTIFACT_ID))
.map(|name| dist.dist_dir.join(name.as_str()))
.collect::<Vec<_>>();
Some((set, files))
} else {
Expand Down
2 changes: 1 addition & 1 deletion cargo-dist/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ fn apply_dist_to_metadata(metadata: &mut toml_edit::Item, meta: &DistMetadata) {
table,
"checksum",
"# Checksums to generate for each App\n",
checksum.map(|c| c.ext()),
checksum.map(|c| c.ext().as_str()),
);

apply_optional_value(
Expand Down
Loading

0 comments on commit 7156093

Please sign in to comment.