mirror of
https://github.com/taiki-e/install-action.git
synced 2026-04-21 15:10:27 +00:00
Support artifact attestations verification
This commit is contained in:
@@ -10,6 +10,10 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Support artifact attestations verification for `biome`, `cargo-cyclonedx`, `cargo-hack`, `cargo-llvm-cov`, `cargo-minimal-versions`, `cargo-no-dev-deps`, `martin`, `parse-changelog`, `parse-dockerfile`, `prek`, `uv`, `wasmtime`, `zizmor`, and `zola`. ([#1606](https://github.com/taiki-e/install-action/pull/1606))
|
||||||
|
|
||||||
|
- Update `biome@latest` to 2.4.8.
|
||||||
|
|
||||||
- Update `tombi@latest` to 0.9.8.
|
- Update `tombi@latest` to 0.9.8.
|
||||||
|
|
||||||
- Update `parse-dockerfile@latest` to 0.1.5.
|
- Update `parse-dockerfile@latest` to 0.1.5.
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ When installing the tool from GitHub Releases, this action will download the too
|
|||||||
|
|
||||||
Additionally, this action will also verify SHA256 checksums for downloaded files in all tools installed from GitHub Releases. This is enabled by default and can be disabled by setting the `checksum` input option to `false`.
|
Additionally, this action will also verify SHA256 checksums for downloaded files in all tools installed from GitHub Releases. This is enabled by default and can be disabled by setting the `checksum` input option to `false`.
|
||||||
|
|
||||||
Additionally, we also verify signature if the tool distributes signed archives. Signature verification is done at the stage of getting the checksum, so disabling the checksum will also disable signature verification.
|
Additionally, we also verify [artifact attestations](https://docs.github.com/en/actions/concepts/security/artifact-attestations) or signature if the tool publishes artifact attestations or distributes signed archives. Verification is done at the stage of getting the checksum, so disabling the checksum will also disable verification.
|
||||||
|
|
||||||
See the linked documentation for information on security when installed using [snap](https://snapcraft.io/docs) or [cargo-binstall](https://github.com/cargo-bins/cargo-binstall#faq).
|
See the linked documentation for information on security when installed using [snap](https://snapcraft.io/docs) or [cargo-binstall](https://github.com/cargo-bins/cargo-binstall#faq).
|
||||||
|
|
||||||
|
|||||||
2467
manifests/biome.json
generated
2467
manifests/biome.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,16 @@
|
|||||||
"repository": "https://github.com/biomejs/biome",
|
"repository": "https://github.com/biomejs/biome",
|
||||||
"website": "https://biomejs.dev",
|
"website": "https://biomejs.dev",
|
||||||
"license_markdown": "[Apache-2.0](https://github.com/biomejs/biome/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/biomejs/biome/blob/main/LICENSE-MIT)",
|
"license_markdown": "[Apache-2.0](https://github.com/biomejs/biome/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/biomejs/biome/blob/main/LICENSE-MIT)",
|
||||||
"tag_prefix": "cli/v",
|
"tag_prefix": ["@biomejs/biome@", "cli/v"],
|
||||||
"bin": "${package}${exe}",
|
"bin": "${package}${exe}",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 2.3.9",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {
|
"x86_64_linux_gnu": {
|
||||||
"asset_name": "${package}-linux-x64"
|
"asset_name": "${package}-linux-x64"
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"bin": "${package}-${rust_target}/${package}${exe}",
|
"bin": "${package}-${rust_target}/${package}${exe}",
|
||||||
"version_range": ">= 0.5.0",
|
"version_range": ">= 0.5.0",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.5.4",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {
|
"x86_64_linux_gnu": {
|
||||||
"asset_name": "${package}-linux-amd64.tar.gz"
|
"asset_name": "${package}-linux-amd64.tar.gz"
|
||||||
|
|||||||
@@ -8,6 +8,14 @@
|
|||||||
"${package}-${rust_target}.zip",
|
"${package}-${rust_target}.zip",
|
||||||
"${package}-v${version}-${rust_target}.zip"
|
"${package}-v${version}-${rust_target}.zip"
|
||||||
],
|
],
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.6.44",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {},
|
"x86_64_linux_gnu": {},
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.8.5",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.1.37",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.2.23",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
"bin": ["${package}${exe}", "${package}-cp${exe}"],
|
"bin": ["${package}${exe}", "${package}-cp${exe}"],
|
||||||
"version_range": ">= 1.0.0",
|
"version_range": ">= 1.0.0",
|
||||||
|
"signing": {
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/ci.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
"${package}-${rust_target}.tar.gz",
|
"${package}-${rust_target}.tar.gz",
|
||||||
"${package}-${rust_target}.zip"
|
"${package}-${rust_target}.zip"
|
||||||
],
|
],
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.6.16",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {},
|
"x86_64_linux_gnu": {},
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.1.5",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "taiki-e/github-actions/.github/workflows/rust-release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
"bin": "${package}-${rust_target}/${package}${exe}",
|
"bin": "${package}-${rust_target}/${package}${exe}",
|
||||||
"version_range": ">= 0.2.20",
|
"version_range": ">= 0.2.20",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.3.1",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"bin": "${package}${exe}",
|
"bin": "${package}${exe}",
|
||||||
"version_range": ">= 0.62.0",
|
"version_range": ">= 0.62.0",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.69.4",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/reusable-release.yaml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {
|
"x86_64_linux_gnu": {
|
||||||
"asset_name": "${package}_${version}_Linux-64bit.tar.gz"
|
"asset_name": "${package}_${version}_Linux-64bit.tar.gz"
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"license_markdown": "[Apache-2.0](https://github.com/astral-sh/uv/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/astral-sh/uv/blob/main/LICENSE-MIT)",
|
"license_markdown": "[Apache-2.0](https://github.com/astral-sh/uv/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/astral-sh/uv/blob/main/LICENSE-MIT)",
|
||||||
"tag_prefix": "",
|
"tag_prefix": "",
|
||||||
"version_range": ">= 0.8.16",
|
"version_range": ">= 0.8.16",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.9.13",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {
|
"x86_64_linux_musl": {
|
||||||
"asset_name": "${package}-x86_64-unknown-linux-musl.tar.gz",
|
"asset_name": "${package}-x86_64-unknown-linux-musl.tar.gz",
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
"tag_prefix": "wash-v",
|
"tag_prefix": "wash-v",
|
||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}${exe}",
|
"asset_name": "${package}-${rust_target}${exe}",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 2.0.0",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/wash.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
"rust_crate": "${package}-cli",
|
"rust_crate": "${package}-cli",
|
||||||
"asset_name": "${package}-v${version}-${rust_target_arch}-${rust_target_os}.tar.xz",
|
"asset_name": "${package}-v${version}-${rust_target_arch}-${rust_target_os}.tar.xz",
|
||||||
"bin": "${package}-v${version}-${rust_target_arch}-${rust_target_os}/${package}${exe}",
|
"bin": "${package}-v${version}-${rust_target_arch}-${rust_target_os}/${package}${exe}",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 28.0.0",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/publish-artifacts.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {},
|
"x86_64_linux_gnu": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -4,6 +4,13 @@
|
|||||||
"rust_crate": "${package}",
|
"rust_crate": "${package}",
|
||||||
"asset_name": "${package}-${rust_target}.tar.gz",
|
"asset_name": "${package}-${rust_target}.tar.gz",
|
||||||
"version_range": ">= 1.9.0",
|
"version_range": ">= 1.9.0",
|
||||||
|
"signing": {
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release-binaries.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {},
|
"x86_64_linux_gnu": {},
|
||||||
"x86_64_macos": {},
|
"x86_64_macos": {},
|
||||||
|
|||||||
@@ -2,6 +2,14 @@
|
|||||||
"repository": "https://github.com/getzola/zola",
|
"repository": "https://github.com/getzola/zola",
|
||||||
"tag_prefix": "v",
|
"tag_prefix": "v",
|
||||||
"asset_name": "${package}-v${version}-${rust_target}.tar.gz",
|
"asset_name": "${package}-v${version}-${rust_target}.tar.gz",
|
||||||
|
"signing": {
|
||||||
|
"version_range": ">= 0.20.0",
|
||||||
|
"kind": {
|
||||||
|
"gh-attestation": {
|
||||||
|
"signer-workflow": "${repo}/.github/workflows/release.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"x86_64_linux_gnu": {},
|
"x86_64_linux_gnu": {},
|
||||||
"x86_64_linux_musl": {},
|
"x86_64_linux_musl": {},
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub struct BaseManifest {
|
|||||||
/// Markdown syntax for links to licenses. Automatically detected if possible.
|
/// Markdown syntax for links to licenses. Automatically detected if possible.
|
||||||
pub license_markdown: Option<String>,
|
pub license_markdown: Option<String>,
|
||||||
/// Prefix of release tag.
|
/// Prefix of release tag.
|
||||||
pub tag_prefix: String,
|
pub tag_prefix: StringOrArray,
|
||||||
/// Crate name, if this is Rust crate.
|
/// Crate name, if this is Rust crate.
|
||||||
pub rust_crate: Option<String>,
|
pub rust_crate: Option<String>,
|
||||||
pub default_major_version: Option<String>,
|
pub default_major_version: Option<String>,
|
||||||
@@ -67,6 +67,7 @@ impl BaseManifest {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Signing {
|
pub struct Signing {
|
||||||
|
pub version_range: Option<String>,
|
||||||
pub kind: SigningKind,
|
pub kind: SigningKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +75,10 @@ pub struct Signing {
|
|||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub enum SigningKind {
|
pub enum SigningKind {
|
||||||
|
/// gh attestation
|
||||||
|
/// <https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations>
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
GhAttestation { signer_workflow: String },
|
||||||
/// algorithm: minisign
|
/// algorithm: minisign
|
||||||
/// public key: package.metadata.binstall.signing.pubkey at Cargo.toml
|
/// public key: package.metadata.binstall.signing.pubkey at Cargo.toml
|
||||||
/// <https://github.com/cargo-bins/cargo-binstall/blob/HEAD/SIGNING.md>
|
/// <https://github.com/cargo-bins/cargo-binstall/blob/HEAD/SIGNING.md>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod process;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
@@ -15,7 +18,7 @@ use anyhow::{Context as _, Result, bail};
|
|||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use install_action_internal_codegen::{
|
use install_action_internal_codegen::{
|
||||||
BaseManifest, HostPlatform, Manifest, ManifestDownloadInfo, ManifestRef, ManifestTemplate,
|
BaseManifest, HostPlatform, Manifest, ManifestDownloadInfo, ManifestRef, ManifestTemplate,
|
||||||
ManifestTemplateDownloadInfo, Manifests, Signing, SigningKind, Version, workspace_root,
|
ManifestTemplateDownloadInfo, Manifests, SigningKind, Version, workspace_root,
|
||||||
};
|
};
|
||||||
use spdx::expression::{ExprNode, ExpressionReq, Operator};
|
use spdx::expression::{ExprNode, ExpressionReq, Operator};
|
||||||
|
|
||||||
@@ -76,7 +79,14 @@ fn main() -> Result<()> {
|
|||||||
if release.prerelease {
|
if release.prerelease {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let version = release.tag_name.strip_prefix(&base_info.tag_prefix)?;
|
let mut version = None;
|
||||||
|
for tag_prefix in base_info.tag_prefix.as_slice() {
|
||||||
|
if let Some(v) = release.tag_name.strip_prefix(tag_prefix) {
|
||||||
|
version = Some(v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let version = version?;
|
||||||
let mut semver_version = version.parse::<semver::Version>();
|
let mut semver_version = version.parse::<semver::Version>();
|
||||||
if semver_version.is_err() {
|
if semver_version.is_err() {
|
||||||
if let Some(default_major_version) = &base_info.default_major_version {
|
if let Some(default_major_version) = &base_info.default_major_version {
|
||||||
@@ -215,15 +225,15 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let version_req: Option<semver::VersionReq> = match version_req {
|
let version_req: semver::VersionReq = match version_req {
|
||||||
_ if latest_only => {
|
_ if latest_only => {
|
||||||
let req = format!("={}", releases.first_key_value().unwrap().0.0).parse()?;
|
let req = format!("={}", releases.first_key_value().unwrap().0.0).parse()?;
|
||||||
eprintln!("update manifest for versions '{req}'");
|
eprintln!("update manifest for versions '{req}'");
|
||||||
Some(req)
|
req
|
||||||
}
|
}
|
||||||
None => match base_info.version_range {
|
None => match base_info.version_range {
|
||||||
Some(version_range) => Some(version_range.parse()?),
|
Some(version_range) => version_range.parse()?,
|
||||||
None => Some(">= 0.0.1".parse()?), // HACK: ignore pre-releases
|
None => ">= 0.0.1".parse()?, // HACK: ignore pre-releases
|
||||||
},
|
},
|
||||||
Some(version_req) => {
|
Some(version_req) => {
|
||||||
for version in manifests.map.keys() {
|
for version in manifests.map.keys() {
|
||||||
@@ -247,17 +257,15 @@ fn main() -> Result<()> {
|
|||||||
version_req.parse()?
|
version_req.parse()?
|
||||||
};
|
};
|
||||||
eprintln!("update manifest for versions '{req}'");
|
eprintln!("update manifest for versions '{req}'");
|
||||||
Some(req)
|
req
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
let mut buf2 = vec![];
|
let mut buf2 = vec![];
|
||||||
for (Reverse(semver_version), (version, release)) in &releases {
|
for (Reverse(semver_version), (version, release)) in &releases {
|
||||||
if let Some(version_req) = &version_req {
|
if !version_req.matches(semver_version) {
|
||||||
if !version_req.matches(semver_version) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specifically skip versions of xbuild with build metadata.
|
// Specifically skip versions of xbuild with build metadata.
|
||||||
@@ -274,6 +282,28 @@ fn main() -> Result<()> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let signing_version_req: Option<semver::VersionReq> = match &base_info.signing {
|
||||||
|
Some(signing) => {
|
||||||
|
match &signing.version_range {
|
||||||
|
Some(version_range) => Some(version_range.parse()?),
|
||||||
|
None => Some(">= 0.0.1".parse()?), // HACK: ignore pre-releases
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Some(asset) = release.assets.iter().find(|asset| {
|
||||||
|
asset.name.contains(".asc")
|
||||||
|
|| asset.name.contains(".gpg")
|
||||||
|
|| asset.name.contains(".sig")
|
||||||
|
}) {
|
||||||
|
eprintln!(
|
||||||
|
"{package} may supports other signing verification method using {}",
|
||||||
|
asset.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut download_info = BTreeMap::new();
|
let mut download_info = BTreeMap::new();
|
||||||
let mut pubkey = None;
|
let mut pubkey = None;
|
||||||
for (&platform, base_download_info) in &base_info.platform {
|
for (&platform, base_download_info) in &base_info.platform {
|
||||||
@@ -323,6 +353,7 @@ fn main() -> Result<()> {
|
|||||||
if let Some(entry) = manifest.download_info.get(&platform) {
|
if let Some(entry) = manifest.download_info.get(&platform) {
|
||||||
if entry.etag == etag {
|
if entry.etag == etag {
|
||||||
eprintln!("existing etag matched");
|
eprintln!("existing etag matched");
|
||||||
|
// NB: Comment out these two lines when adding verification for old release.
|
||||||
download_info.insert(platform, entry.clone());
|
download_info.insert(platform, entry.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -354,81 +385,103 @@ fn main() -> Result<()> {
|
|||||||
eprintln!("{hash} *{asset_name}");
|
eprintln!("{hash} *{asset_name}");
|
||||||
let bin_url = &url;
|
let bin_url = &url;
|
||||||
|
|
||||||
match base_info.signing {
|
if let Some(signing) = &base_info.signing {
|
||||||
Some(Signing { kind: SigningKind::MinisignBinstall }) => {
|
match &signing.kind {
|
||||||
let url = url.clone() + ".sig";
|
_ if !signing_version_req.as_ref().unwrap().matches(semver_version) => {}
|
||||||
let sig_download_cache = &download_cache.with_extension(format!(
|
SigningKind::GhAttestation { signer_workflow } => {
|
||||||
"{}.sig",
|
eprintln!("verifying {url} with gh attestation verify");
|
||||||
download_cache.extension().unwrap_or_default().to_str().unwrap()
|
let signer_workflow = signer_workflow.replace("${repo}", repo);
|
||||||
));
|
cmd!(
|
||||||
eprint!("downloading {url} for signature validation ... ");
|
"gh",
|
||||||
let sig = if sig_download_cache.is_file() {
|
"attestation",
|
||||||
eprintln!("already downloaded");
|
"verify",
|
||||||
minisign_verify::Signature::from_file(sig_download_cache)?
|
"--repo",
|
||||||
} else {
|
repo,
|
||||||
let buf = download(&url)?.into_string()?;
|
"--signer-workflow",
|
||||||
eprintln!("download complete");
|
signer_workflow,
|
||||||
fs::write(sig_download_cache, &buf)?;
|
&download_cache
|
||||||
minisign_verify::Signature::decode(&buf)?
|
)
|
||||||
};
|
.run()?;
|
||||||
|
}
|
||||||
|
SigningKind::MinisignBinstall => {
|
||||||
|
let url = url.clone() + ".sig";
|
||||||
|
let sig_download_cache = &download_cache.with_extension(format!(
|
||||||
|
"{}.sig",
|
||||||
|
download_cache.extension().unwrap_or_default().to_str().unwrap()
|
||||||
|
));
|
||||||
|
eprint!("downloading {url} for signature validation ... ");
|
||||||
|
let sig = if sig_download_cache.is_file() {
|
||||||
|
eprintln!("already downloaded");
|
||||||
|
minisign_verify::Signature::from_file(sig_download_cache)?
|
||||||
|
} else {
|
||||||
|
let buf = download(&url)?.into_string()?;
|
||||||
|
eprintln!("download complete");
|
||||||
|
fs::write(sig_download_cache, &buf)?;
|
||||||
|
minisign_verify::Signature::decode(&buf)?
|
||||||
|
};
|
||||||
|
|
||||||
let Some(crates_io_info) = &crates_io_info else {
|
let Some(crates_io_info) = &crates_io_info else {
|
||||||
bail!("signing kind minisign-binstall is supported only for rust crate");
|
bail!(
|
||||||
};
|
"signing kind minisign-binstall is supported only for rust crate"
|
||||||
let v =
|
);
|
||||||
crates_io_info.versions.iter().find(|v| v.num == *semver_version).unwrap();
|
};
|
||||||
let url = format!("https://crates.io{}", v.dl_path);
|
let v = crates_io_info
|
||||||
let crate_download_cache =
|
.versions
|
||||||
&download_cache_dir.join(format!("{version}-Cargo.toml"));
|
.iter()
|
||||||
eprint!("downloading {url} for signature verification ... ");
|
.find(|v| v.num == *semver_version)
|
||||||
if crate_download_cache.is_file() {
|
.unwrap();
|
||||||
eprintln!("already downloaded");
|
let url = format!("https://crates.io{}", v.dl_path);
|
||||||
} else {
|
let crate_download_cache =
|
||||||
download(&url)?.into_reader().read_to_end(&mut buf2)?;
|
&download_cache_dir.join(format!("{version}-Cargo.toml"));
|
||||||
let hash = ring::digest::digest(&ring::digest::SHA256, &buf2);
|
eprint!("downloading {url} for signature verification ... ");
|
||||||
if format!("{hash:?}").strip_prefix("SHA256:").unwrap() != v.checksum {
|
if crate_download_cache.is_file() {
|
||||||
bail!("checksum mismatch for {url}");
|
eprintln!("already downloaded");
|
||||||
}
|
} else {
|
||||||
let decoder = flate2::read::GzDecoder::new(&*buf2);
|
download(&url)?.into_reader().read_to_end(&mut buf2)?;
|
||||||
let mut archive = tar::Archive::new(decoder);
|
let hash = ring::digest::digest(&ring::digest::SHA256, &buf2);
|
||||||
for entry in archive.entries()? {
|
if format!("{hash:?}").strip_prefix("SHA256:").unwrap() != v.checksum {
|
||||||
let mut entry = entry?;
|
bail!("checksum mismatch for {url}");
|
||||||
let path = entry.path()?;
|
|
||||||
if path.file_name() == Some(OsStr::new("Cargo.toml")) {
|
|
||||||
entry.unpack(crate_download_cache)?;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
let decoder = flate2::read::GzDecoder::new(&*buf2);
|
||||||
|
let mut archive = tar::Archive::new(decoder);
|
||||||
|
for entry in archive.entries()? {
|
||||||
|
let mut entry = entry?;
|
||||||
|
let path = entry.path()?;
|
||||||
|
if path.file_name() == Some(OsStr::new("Cargo.toml")) {
|
||||||
|
entry.unpack(crate_download_cache)?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf2.clear();
|
||||||
|
eprintln!("download complete");
|
||||||
}
|
}
|
||||||
buf2.clear();
|
if pubkey.is_none() {
|
||||||
eprintln!("download complete");
|
let cargo_manifest = toml::de::from_str::<cargo_manifest::Manifest>(
|
||||||
|
&fs::read_to_string(crate_download_cache)?,
|
||||||
|
)?;
|
||||||
|
eprintln!(
|
||||||
|
"algorithm: {}",
|
||||||
|
cargo_manifest.package.metadata.binstall.signing.algorithm
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"pubkey: {}",
|
||||||
|
cargo_manifest.package.metadata.binstall.signing.pubkey
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cargo_manifest.package.metadata.binstall.signing.algorithm,
|
||||||
|
"minisign"
|
||||||
|
);
|
||||||
|
pubkey = Some(minisign_verify::PublicKey::from_base64(
|
||||||
|
&cargo_manifest.package.metadata.binstall.signing.pubkey,
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
let pubkey = pubkey.as_ref().unwrap();
|
||||||
|
eprint!("verifying signature for {bin_url} ... ");
|
||||||
|
let allow_legacy = false;
|
||||||
|
pubkey.verify(&buf, &sig, allow_legacy)?;
|
||||||
|
eprintln!("done");
|
||||||
}
|
}
|
||||||
if pubkey.is_none() {
|
|
||||||
let cargo_manifest = toml::de::from_str::<cargo_manifest::Manifest>(
|
|
||||||
&fs::read_to_string(crate_download_cache)?,
|
|
||||||
)?;
|
|
||||||
eprintln!(
|
|
||||||
"algorithm: {}",
|
|
||||||
cargo_manifest.package.metadata.binstall.signing.algorithm
|
|
||||||
);
|
|
||||||
eprintln!(
|
|
||||||
"pubkey: {}",
|
|
||||||
cargo_manifest.package.metadata.binstall.signing.pubkey
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
cargo_manifest.package.metadata.binstall.signing.algorithm,
|
|
||||||
"minisign"
|
|
||||||
);
|
|
||||||
pubkey = Some(minisign_verify::PublicKey::from_base64(
|
|
||||||
&cargo_manifest.package.metadata.binstall.signing.pubkey,
|
|
||||||
)?);
|
|
||||||
}
|
|
||||||
let pubkey = pubkey.as_ref().unwrap();
|
|
||||||
eprint!("verifying signature for {bin_url} ... ");
|
|
||||||
let allow_legacy = false;
|
|
||||||
pubkey.verify(&buf, &sig, allow_legacy)?;
|
|
||||||
eprintln!("done");
|
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
download_info.insert(
|
download_info.insert(
|
||||||
|
|||||||
155
tools/codegen/src/process.rs
Normal file
155
tools/codegen/src/process.rs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt, format,
|
||||||
|
process::{Command, ExitStatus, Output},
|
||||||
|
str,
|
||||||
|
string::{String, ToString as _},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{Context as _, Error, Result};
|
||||||
|
|
||||||
|
macro_rules! cmd {
|
||||||
|
($program:expr $(, $arg:expr)* $(,)?) => {{
|
||||||
|
let mut _cmd = std::process::Command::new($program);
|
||||||
|
$(
|
||||||
|
_cmd.arg($arg);
|
||||||
|
)*
|
||||||
|
$crate::process::ProcessBuilder::from_std(_cmd)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// A builder for an external process, inspired by https://github.com/rust-lang/cargo/blob/0.47.0/src/cargo/util/process_builder.rs
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) struct ProcessBuilder {
|
||||||
|
cmd: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessBuilder {
|
||||||
|
pub(crate) fn from_std(cmd: Command) -> Self {
|
||||||
|
Self { cmd }
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub(crate) fn into_std(self) -> Command {
|
||||||
|
// self.cmd
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Adds an argument to pass to the program.
|
||||||
|
// pub(crate) fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
|
||||||
|
// self.cmd.arg(arg.as_ref());
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Adds multiple arguments to pass to the program.
|
||||||
|
// pub(crate) fn args(&mut self, args: impl IntoIterator<Item = impl AsRef<OsStr>>) -> &mut Self {
|
||||||
|
// self.cmd.args(args);
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Set a variable in the process's environment.
|
||||||
|
// pub(crate) fn env(&mut self, key: impl AsRef<OsStr>, val: impl AsRef<OsStr>) -> &mut Self {
|
||||||
|
// self.cmd.env(key.as_ref(), val.as_ref());
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// Executes a process, waiting for completion, and mapping non-zero exit
|
||||||
|
/// status to an error.
|
||||||
|
pub(crate) fn run(&mut self) -> Result<()> {
|
||||||
|
let status = self.cmd.status().with_context(|| {
|
||||||
|
process_error(format!("could not execute process {self}"), None, None)
|
||||||
|
})?;
|
||||||
|
if status.success() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(process_error(
|
||||||
|
format!("process didn't exit successfully: {self}"),
|
||||||
|
Some(status),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// Executes a process, captures its stdio output, returning the captured
|
||||||
|
// /// output, or an error if non-zero exit status.
|
||||||
|
// pub(crate) fn run_with_output(&mut self) -> Result<Output> {
|
||||||
|
// let output = self.cmd.output().with_context(|| {
|
||||||
|
// process_error(format!("could not execute process {self}"), None, None)
|
||||||
|
// })?;
|
||||||
|
// if output.status.success() {
|
||||||
|
// Ok(output)
|
||||||
|
// } else {
|
||||||
|
// Err(process_error(
|
||||||
|
// format!("process didn't exit successfully: {self}"),
|
||||||
|
// Some(output.status),
|
||||||
|
// Some(&output),
|
||||||
|
// ))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Executes a process, captures its stdio output, returning the captured
|
||||||
|
// /// standard output as a `String`.
|
||||||
|
// pub(crate) fn read(&mut self) -> Result<String> {
|
||||||
|
// let mut output = String::from_utf8(self.run_with_output()?.stdout)
|
||||||
|
// .with_context(|| format!("failed to parse output from {self}"))?;
|
||||||
|
// while output.ends_with('\n') || output.ends_with('\r') {
|
||||||
|
// output.pop();
|
||||||
|
// }
|
||||||
|
// Ok(output)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://github.com/rust-lang/cargo/blob/0.47.0/src/cargo/util/process_builder.rs
|
||||||
|
impl fmt::Display for ProcessBuilder {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if !f.alternate() {
|
||||||
|
f.write_str("`")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_str(&self.cmd.get_program().to_string_lossy())?;
|
||||||
|
|
||||||
|
for arg in self.cmd.get_args() {
|
||||||
|
write!(f, " {}", arg.to_string_lossy())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.alternate() {
|
||||||
|
f.write_str("`")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://github.com/rust-lang/cargo/blob/0.47.0/src/cargo/util/errors.rs
|
||||||
|
/// Creates a new process error.
|
||||||
|
///
|
||||||
|
/// `status` can be `None` if the process did not launch.
|
||||||
|
/// `output` can be `None` if the process did not launch, or output was not captured.
|
||||||
|
fn process_error(mut msg: String, status: Option<ExitStatus>, output: Option<&Output>) -> Error {
|
||||||
|
match status {
|
||||||
|
Some(s) => {
|
||||||
|
msg.push_str(" (");
|
||||||
|
msg.push_str(&s.to_string());
|
||||||
|
msg.push(')');
|
||||||
|
}
|
||||||
|
None => msg.push_str(" (never executed)"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(out) = output {
|
||||||
|
match str::from_utf8(&out.stdout) {
|
||||||
|
Ok(s) if !s.trim_start().is_empty() => {
|
||||||
|
msg.push_str("\n--- stdout\n");
|
||||||
|
msg.push_str(s);
|
||||||
|
}
|
||||||
|
Ok(_) | Err(_) => {}
|
||||||
|
}
|
||||||
|
match str::from_utf8(&out.stderr) {
|
||||||
|
Ok(s) if !s.trim_start().is_empty() => {
|
||||||
|
msg.push_str("\n--- stderr\n");
|
||||||
|
msg.push_str(s);
|
||||||
|
}
|
||||||
|
Ok(_) | Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error::msg(msg)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user