Skip to content

Conversation

@lovesegfault
Copy link
Member

Motivation

  • feat(libstore): add RequiredSignatures field to binary cache protocol
    • Binary caches can now advertise signature requirements via a new
      RequiredSignatures field in nix-cache-info. This field contains a
      whitespace-separated list of public keys.
  • feat(libstore): add RequireAllSignatures field for multi-party signing
    • Adds a RequireAllSignatures field to nix-cache-info that, when set to 1,
      requires paths to be signed by ALL keys listed in RequiredSignatures rather
      than just one.
  • test(tests/nixos/s3-binary-cache-store): add RequiredSignatures tests
    • Add tests for the RequiredSignatures and RequireAllSignatures fields in
      nix-cache-info:

Context

Fixes: #12491
Supersedes: #14298


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@github-actions github-actions bot added the store Issues and pull requests concerning the Nix store label Oct 20, 2025
Binary caches can now advertise signature requirements via a new
RequiredSignatures field in nix-cache-info. This field contains a
whitespace-separated list of public keys.

When uploading paths to such caches, Nix validates that each path has
at least one valid signature from the required keys. This prevents
accidental uploads of unsigned or incorrectly-signed paths due to
configuration errors (e.g., typos like "secret-key-file" vs "secret-key").

Content-addressed paths are exempt from this check as they are
self-validating.
Adds a RequireAllSignatures field to nix-cache-info that, when set to 1,
requires paths to be signed by ALL keys listed in RequiredSignatures
rather than just one.

This enables multi-party approval workflows where paths must be signed
by multiple independent parties before being uploaded to a cache (e.g.,
dev team, QA team, and release team).

Example nix-cache-info:
  RequiredSignatures: dev:key1... qa:key2... release:key3...
  RequireAllSignatures: 1

Error messages now indicate whether "at least ONE" or "ALL" keys are
required and show the signature count (e.g., "1 out of 3 required").
Add tests for the RequiredSignatures and RequireAllSignatures fields in
nix-cache-info:

- Test unsigned path rejection
- Test correctly signed path acceptance
- Test wrong key signature rejection
- Test content-addressed paths bypass signature requirements
- Test multiple required keys (any one sufficient)
- Test RequireAllSignatures enforcement (all keys required)

Added test packages D-G to avoid signature state pollution across tests.
@lovesegfault lovesegfault force-pushed the nix-store-require-sigs branch from 4a6b6fe to 786871e Compare October 20, 2025 22:30
@lovesegfault
Copy link
Member Author

An open question is that these nix-cache-info fields don't seem to be properly documented anywhere? Where should docs for this go?

@Ericson2314
Copy link
Member

Ericson2314 commented Oct 20, 2025

Oh we are very behind documenting the entire binary cache format. This should definitely be fixed. I imagine that the protocols section would be good. Part of my idea with using more JSON (in a backwards compatible way) is that then we can reuse the same JSON Schema stuff I am doing for this purpose.

@Ericson2314
Copy link
Member

Also my dream would be using Accept, Content-Type, and x-amz-website-redirect-location to migrate completely to JSON without breaking older clients.

config.wantMassQuery.setDefault(value == "1");
} else if (name == "Priority") {
config.priority.setDefault(std::stoi(value));
} else if (name == "RequiredSignatures") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be named RequiredSigners (it's a list of public keys, not a list of signatures).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And actually the name RequiredSigners is misleading if RequireAllSignatures is false. So it should probably be Signers or AllowedSigners.

}
}
}
} else if (name == "RequireAllSignatures") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be NrSignaturesNeeded, taking an arbitrary integer, similar to nix verify's --sigs-needed flag. It might be useful to require e.g. at least 2 valid signatures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation store Issues and pull requests concerning the Nix store

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nix copy --to s3:// will copy unsigned paths to binary cache even if --no-check-sigs isn't used

3 participants