Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions qlty-cli/src/attestation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use anyhow::{bail, Context, Result};
use std::path::Path;
use std::process::Command;
use std::thread;
use std::time::Duration;

const QLTY_OWNER: &str = "qltysh";
const MAX_RETRIES: u32 = 3;
const RETRY_DELAY: Duration = Duration::from_secs(2);

pub fn verify_attestation(archive_path: &Path) -> Result<()> {
if !is_gh_available() {
Expand All @@ -12,18 +16,27 @@ pub fn verify_attestation(archive_path: &Path) -> Result<()> {

eprintln!("Verifying provenance...");

let output = Command::new("gh")
.args([
"attestation",
"verify",
&archive_path.to_string_lossy(),
"--owner",
QLTY_OWNER,
])
.output()
.context("Failed to run gh attestation verify")?;
for attempt in 1..=MAX_RETRIES {
let output = Command::new("gh")
.args([
"attestation",
"verify",
&archive_path.to_string_lossy(),
"--owner",
QLTY_OWNER,
])
.output()
.context("Failed to run gh attestation verify")?;

if output.status.success() {
eprintln!(
" {} Verified SLSA provenance from github.com/{}",
console::style("OK").green().bold(),
QLTY_OWNER
);
return Ok(());
}

if !output.status.success() {
let exit_code = output.status.code();

if exit_code == Some(4) {
Expand All @@ -33,6 +46,17 @@ pub fn verify_attestation(archive_path: &Path) -> Result<()> {

let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);

let combined_output = format!("{}{}", stderr, stdout);
if is_transient_error(&combined_output) && attempt < MAX_RETRIES {
eprintln!(
" Transient error during verification (attempt {}/{}), retrying...",
attempt, MAX_RETRIES
);
thread::sleep(RETRY_DELAY * attempt);
continue;
}

let mut message = "Provenance verification failed".to_string();
if !stderr.is_empty() {
message.push_str(&format!(": {}", stderr.trim()));
Expand All @@ -42,12 +66,11 @@ pub fn verify_attestation(archive_path: &Path) -> Result<()> {
bail!(message);
}

eprintln!(
" {} Verified SLSA provenance from github.com/{}",
console::style("OK").green().bold(),
QLTY_OWNER
);
Ok(())
unreachable!()
}

fn is_transient_error(output: &str) -> bool {
output.contains("HTTP 5") || output.contains("connection reset")
}

fn is_gh_available() -> bool {
Expand Down
Loading