Skip to content

Cache encoding/layout incompatibility causes request failure #141

@woodruffw

Description

@woodruffw

Hi there!

I was experimenting with upgrading zizmor to reqwest 0.13, which includes upgrading http-cache-reqwest and reqwest-middleware for compatibility reasons.

Expected behavior

Invalid or incompatible (e.g. for legacy reasons) cache entries should be silently ignored (potentially with logging), rather causing a hard failure that takes down the entire request.

Actual behavior

Everything built fine and appears to work on a machine with no pre-existing cache (or only fresh cache entries). However, if I perform an invocation that hits the network on a machine that does have a pre-existing cache, I get this error:

% GH_TOKEN=$(gh auth token) ./target/debug/zizmor .github/workflows/benchmark.yml
🌈 zizmor v1.22.0
fatal: no audit was performed
'known-vulnerable-actions' audit failed on file://.github/workflows/benchmark.yml

Caused by:
    0: error in 'known-vulnerable-actions' audit
    1: request error while accessing GitHub API
    2: Cache error: invalid value: integer `28`, expected variant index 0 <= i < 1

If I blow away the cache (at ~/.cache/zizmor) it disappears, although I can make it reappear reliably by running a previous release, presumably creating the old (incompatible) entries again:

% GH_TOKEN=$(gh auth token) zizmor .github/workflows/benchmark.yml
🌈 zizmor v1.22.0
 INFO audit: zizmor: 🌈 completed .github/workflows/benchmark.yml
No findings to report. Good job!

...and then if I run GH_TOKEN=$(gh auth token) ./target/debug/zizmor .github/workflows/benchmark.yml, the error reappears.

Conversely, if I blow away the cache and run the new version first, the old version also fails, but with a different (less detailed) error:

% GH_TOKEN=$(gh auth token) zizmor .github/workflows/benchmark.yml
🌈 zizmor v1.22.0
fatal: no audit was performed
'known-vulnerable-actions' audit failed on file://.github/workflows/benchmark.yml

Caused by:
    0: error in 'known-vulnerable-actions' audit
    1: request error while accessing GitHub API
    2: Cache error: io error:

The previous (currently released) version is using http-cache-reqwest 1.0.0-alpha.2; the new (unreleased) version is using http-cache-reqwest 1.0.0-alpha.3.

I'm pretty sure this is an error within http-cache, and not within another part of reqwest or reqwest-middleware. In particular, this looks like a likely source:

// Serialize as enum (needed for bincode to match deserialization)
impl Serialize for HttpHeaders {
fn serialize<S>(
&self,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
// Serialize the enum properly with variant tags
// This matches how RawHttpHeaders deserializes
match self {
HttpHeaders::Modern(modern) => serializer
.serialize_newtype_variant("HttpHeaders", 0, "Modern", modern),
#[cfg(feature = "http-headers-compat")]
HttpHeaders::Legacy(legacy) => serializer
.serialize_newtype_variant("HttpHeaders", 1, "Legacy", legacy),
}
}
}
// Deserialize: Need to handle enum variant properly for bincode
impl<'de> Deserialize<'de> for HttpHeaders {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Bincode serializes enums with a variant index
// We need to deserialize it properly as an enum
#[cfg(feature = "http-headers-compat")]
{
#[derive(Deserialize)]
enum RawHttpHeaders {
Modern(HashMap<String, Vec<String>>),
Legacy(HashMap<String, String>),
}
match RawHttpHeaders::deserialize(deserializer)? {
RawHttpHeaders::Modern(m) => Ok(HttpHeaders::Modern(m)),
RawHttpHeaders::Legacy(l) => Ok(HttpHeaders::Legacy(l)),
}
}
#[cfg(not(feature = "http-headers-compat"))]
{
#[derive(Deserialize)]
enum RawHttpHeaders {
Modern(HashMap<String, Vec<String>>),
}
match RawHttpHeaders::deserialize(deserializer)? {
RawHttpHeaders::Modern(m) => Ok(HttpHeaders::Modern(m)),
}
}
}
}

(I noticed the http-headers-compat feature, but that seems to only be exposed on http-cache and not http-cache-reqwest.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions