1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-12 20:11:03 +01:00

Merge pull request #14743 from NixOS/sri-in-json

Use SRI hash (strings) as the official JSON format for Hash after all
This commit is contained in:
John Ericson 2025-12-08 22:25:11 +00:00 committed by GitHub
commit bc0af77ba7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 84 additions and 353 deletions

View file

@ -49,17 +49,10 @@ The new structured format follows the [JSON guidelines](@docroot@/development/js
Content address is now a structured JSON object instead of a string: Content address is now a structured JSON object instead of a string:
- Old: `"ca": "fixed:r:sha256:1abc..."` - Old: `"ca": "fixed:r:sha256:1abc..."`
- New: `"ca": {"method": "nar", "hash": {"algorithm": "sha256", "format": "base16", "hash": "10c209fa..."}}` - New: `"ca": {"method": "nar", "hash": "sha256-ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="}`
- Still `null` values for input-addressed store objects - Still `null` values for input-addressed store objects
- **Structured hash fields**: The `hash` field uses the [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) format like other hashes.
Hash values (`narHash` and `downloadHash`) are now structured JSON objects instead of strings:
- Old: `"narHash": "sha256:FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="`
- New: `"narHash": {"algorithm": "sha256", "format": "base16", "hash": "15e3c5608946..."}`
- Same structure applies to `downloadHash` in NAR info contexts
- The `format` field is always `"base16"` (hexadecimal)
Nix currently only produces, and doesn't consume this format. Nix currently only produces, and doesn't consume this format.
@ -87,7 +80,7 @@ The derivation JSON format has been updated from version 3 to version 4:
- **Consistent content addresses**: - **Consistent content addresses**:
Floating content-addressed outputs now use structured JSON format. Fixed content-addressed outputs now use structured JSON format.
This is the same format as `ca` in store path info (after the new version). This is the same format as `ca` in store path info (after the new version).
Version 3 and earlier formats are *not* accepted when reading. Version 3 and earlier formats are *not* accepted when reading.

View file

@ -5,13 +5,13 @@
### SHA-256 ### SHA-256
```json ```json
{{#include schema/hash-v1/sha256-base16.json}} {{#include schema/hash-v1/sha256.json}}
``` ```
### BLAKE3 ### BLAKE3
```json ```json
{{#include schema/hash-v1/blake3-base16.json}} {{#include schema/hash-v1/blake3.json}}
``` ```
<!-- need to convert YAML to JSON first <!-- need to convert YAML to JSON first

View file

@ -4,36 +4,13 @@ title: Hash
description: | description: |
A cryptographic hash value used throughout Nix for content addressing and integrity verification. A cryptographic hash value used throughout Nix for content addressing and integrity verification.
This schema describes the JSON representation of Nix's `Hash` type. This schema describes the JSON representation of Nix's `Hash` type as an [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) string.
type: object type: string
properties: pattern: "^(blake3|md5|sha1|sha256|sha512)-[A-Za-z0-9+/]+=*$"
algorithm: examples:
"$ref": "#/$defs/algorithm" - "sha256-ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="
format: - "sha512-IEqPxt2oLwoM7XvrjgikFlfBbvRosiioJ5vjMacDwzWW/RXBOxsH+aodO+pXeJygMa2Fx6cd1wNU7GMSOMo0RQ=="
type: string
enum:
- base16
title: Hash format
description: |
The encoding format of the hash value.
`base16` (lowercase hexadecimal) is the only format that is currently supported for JSON serialization.
This field exists primarily to reduce ambiguity about what the hash means.
It would also help us support other formats in the future, but there are no concrete plans to do so at this.
hash:
type: string
title: Hash
description: |
The encoded hash value, itself.
It is specified in the format specified by the `format` field.
It must be the right length for the hash algorithm specified in the `algorithm` field, also.
The hash value does not include any algorithm prefix.
required:
- algorithm
- format
- hash
additionalProperties: false
"$defs": "$defs":
algorithm: algorithm:
type: string type: string

View file

@ -32,8 +32,8 @@ schemas = [
'stem' : 'hash', 'stem' : 'hash',
'schema' : schema_dir / 'hash-v1.yaml', 'schema' : schema_dir / 'hash-v1.yaml',
'files' : [ 'files' : [
'sha256-base16.json', 'sha256.json',
'blake3-base16.json', 'blake3.json',
], ],
}, },
{ {

View file

@ -1,26 +1,14 @@
[ [
{ {
"hash": { "hash": "sha256-+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0=",
"algorithm": "sha256",
"format": "base16",
"hash": "f9773d2e5ea670f96dc1a7b0ae4fc1010e7a6371b94ffff0ce1294734ceb62ed"
},
"method": "text" "method": "text"
}, },
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
}, },
{ {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
} }
] ]

View file

@ -1,11 +1,7 @@
[ [
null, null,
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
} }
] ]

View file

@ -1,8 +1,4 @@
{ {
"hash": { "hash": "sha256-9vLqj0XYoFfJVmoz+ZR02i5camYE1zYSFlDicwxvsKM=",
"algorithm": "sha256",
"format": "base16",
"hash": "f6f2ea8f45d8a057c9566a33f99474da2e5c6a6604d736121650e2730c6fb0a3"
},
"method": "nar" "method": "nar"
} }

View file

@ -1,8 +1,4 @@
{ {
"hash": { "hash": "sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts=",
"algorithm": "sha256",
"format": "base16",
"hash": "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"
},
"method": "text" "method": "text"
} }

View file

@ -1,8 +1,4 @@
{ {
"hash": { "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",
"algorithm": "sha256",
"format": "base16",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f"
},
"method": "flat" "method": "flat"
} }

View file

@ -1,8 +1,4 @@
{ {
"hash": { "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",
"algorithm": "sha256",
"format": "base16",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f"
},
"method": "nar" "method": "nar"
} }

View file

@ -1,8 +1,4 @@
{ {
"hash": { "hash": "sha256-iUUXyRY8iW7DGirb0zwGgf1fRbLA7wimTJKgP7l/OQ8=",
"algorithm": "sha256",
"format": "base16",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f"
},
"method": "text" "method": "text"
} }

View file

@ -12,19 +12,11 @@
}, },
"info": { "info": {
"ca": { "ca": {
"hash": { "hash": "sha256-f1eduuSIYC1BofXA1tycF79Ai2NSMJQtUErx5DxLYSU=",
"algorithm": "sha256",
"format": "base16",
"hash": "7f579dbae488602d41a1f5c0d6dc9c17bf408b635230942d504af1e43c4b6125"
},
"method": "nar" "method": "nar"
}, },
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-f1eduuSIYC1BofXA1tycF79Ai2NSMJQtUErx5DxLYSU=",
"algorithm": "sha256",
"format": "base16",
"hash": "7f579dbae488602d41a1f5c0d6dc9c17bf408b635230942d504af1e43c4b6125"
},
"narSize": 120, "narSize": 120,
"references": [], "references": [],
"registrationTime": null, "registrationTime": null,

View file

@ -1,25 +1,13 @@
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"compression": "xz", "compression": "xz",
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"downloadHash": { "downloadHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"downloadSize": 4029176, "downloadSize": 4029176,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,17 +1,9 @@
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,11 +1,7 @@
{ {
"ca": null, "ca": null,
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 0, "narSize": 0,
"references": [], "references": [],
"registrationTime": null, "registrationTime": null,

View file

@ -1,10 +1,6 @@
{ {
"ca": null, "ca": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 0, "narSize": 0,
"references": [], "references": [],
"storeDir": "/nix/store", "storeDir": "/nix/store",

View file

@ -1,18 +1,10 @@
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,17 +1,9 @@
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,26 +1,14 @@
[ [
{ {
"hash": { "hash": "sha256-+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0=",
"algorithm": "sha256",
"format": "base16",
"hash": "f9773d2e5ea670f96dc1a7b0ae4fc1010e7a6371b94ffff0ce1294734ceb62ed"
},
"method": "text" "method": "text"
}, },
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
}, },
{ {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
} }
] ]

View file

@ -1,11 +1,7 @@
[ [
null, null,
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
} }
] ]

View file

@ -2,11 +2,7 @@
{ {
"ca": null, "ca": null,
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"algorithm": "sha256",
"format": "base16",
"hash": "0000000000000000000000000000000000000000000000000000000000000000"
},
"narSize": 34878, "narSize": 34878,
"references": [], "references": [],
"registrationTime": null, "registrationTime": null,
@ -18,11 +14,7 @@
{ {
"ca": null, "ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"algorithm": "sha256",
"format": "base16",
"hash": "0000000000000000000000000000000000000000000000000000000000000000"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv" "g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"

View file

@ -2,11 +2,7 @@
{ {
"ca": null, "ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv" "g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
@ -19,19 +15,11 @@
}, },
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,26 +1,14 @@
[ [
{ {
"hash": { "hash": "sha256-+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0=",
"algorithm": "sha256",
"format": "base16",
"hash": "f9773d2e5ea670f96dc1a7b0ae4fc1010e7a6371b94ffff0ce1294734ceb62ed"
},
"method": "text" "method": "text"
}, },
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
}, },
{ {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
} }
] ]

View file

@ -1,11 +1,7 @@
[ [
null, null,
{ {
"hash": { "hash": "sha1-gGemBoenViNZM3hiwqns/Fgzqwo=",
"algorithm": "sha1",
"format": "base16",
"hash": "8067a60687a7562359337862c2a9ecfc5833ab0a"
},
"method": "flat" "method": "flat"
} }
] ]

View file

@ -2,11 +2,7 @@
{ {
"ca": null, "ca": null,
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [], "references": [],
"registrationTime": 23423, "registrationTime": 23423,
@ -18,11 +14,7 @@
{ {
"ca": null, "ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"references": [ "references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv" "g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"

View file

@ -2,11 +2,7 @@
{ {
"ca": null, "ca": null,
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [], "references": [],
@ -19,11 +15,7 @@
{ {
"ca": null, "ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [ "references": [

View file

@ -2,11 +2,7 @@
{ {
"ca": null, "ca": null,
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [], "references": [],
@ -19,11 +15,7 @@
{ {
"ca": null, "ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", "deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", "path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [ "references": [
@ -41,19 +33,11 @@
}, },
{ {
"ca": { "ca": {
"hash": { "hash": "sha256-EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM=",
"algorithm": "sha256",
"format": "base16",
"hash": "10c209fa0890fe02c85a8c663ca8e7a37cc766bc5b1b29a0cc61b266f64121d3"
},
"method": "nar" "method": "nar"
}, },
"deriver": null, "deriver": null,
"narHash": { "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"algorithm": "sha256",
"format": "base16",
"hash": "15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527"
},
"narSize": 34878, "narSize": 34878,
"path": "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo", "path": "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo",
"references": [ "references": [

View file

@ -1,5 +0,0 @@
{
"algorithm": "blake3",
"format": "base16",
"hash": "9e70ee1449965fb62d049040a1ed06ec377430da6ec13173e7c4fffcd28be980"
}

View file

@ -0,0 +1 @@
"blake3-nnDuFEmWX7YtBJBAoe0G7Dd0MNpuwTFz58T//NKL6YA="

View file

@ -1,5 +0,0 @@
{
"algorithm": "sha256",
"format": "base16",
"hash": "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"
}

View file

@ -1,5 +0,0 @@
{
"algorithm": "sha256",
"format": "base64",
"hash": "8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="
}

View file

@ -1,5 +0,0 @@
{
"algorithm": "sha256",
"format": "nix32",
"hash": "0fz12qc1nillhvhw6bvs4ka18789x8dqaipjb316x4aqdkvw5r7h"
}

View file

@ -0,0 +1 @@
"sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="

View file

@ -0,0 +1 @@
"sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="

View file

@ -1,5 +0,0 @@
{
"algorithm": "sha256",
"format": "base16",
"hash": "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"
}

View file

@ -215,9 +215,6 @@ struct HashJsonTest : virtual HashTest,
::testing::WithParamInterface<std::pair<std::string_view, Hash>> ::testing::WithParamInterface<std::pair<std::string_view, Hash>>
{}; {};
struct HashJsonParseFailureTest : virtual HashTest, ::testing::WithParamInterface<std::string_view>
{};
struct BLAKE3HashJsonTest : virtual HashTest, struct BLAKE3HashJsonTest : virtual HashTest,
BLAKE3HashTest, BLAKE3HashTest,
JsonCharacterizationTest<Hash>, JsonCharacterizationTest<Hash>,
@ -236,14 +233,6 @@ TEST_P(HashJsonTest, to_json)
writeJsonTest(name, value); writeJsonTest(name, value);
} }
TEST_P(HashJsonParseFailureTest, from_json)
{
auto & name = GetParam();
auto path = goldenMaster(Path{name} + ".json");
auto encoded = json::parse(readFile(path));
ASSERT_THROW(nlohmann::adl_serializer<Hash>::from_json(encoded), Error);
}
TEST_P(BLAKE3HashJsonTest, from_json) TEST_P(BLAKE3HashJsonTest, from_json)
{ {
auto & [name, expected] = GetParam(); auto & [name, expected] = GetParam();
@ -256,32 +245,25 @@ TEST_P(BLAKE3HashJsonTest, to_json)
writeJsonTest(name, expected); writeJsonTest(name, expected);
} }
// Round-trip tests (from_json + to_json) for base16 format only
// (to_json always outputs base16)
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
HashJSON, HashJSON,
HashJsonTest, HashJsonTest,
::testing::Values( ::testing::Values(
std::pair{ std::pair{
"simple", "sha256",
hashString(HashAlgorithm::SHA256, "asdf"), hashString(HashAlgorithm::SHA256, "asdf"),
}, },
std::pair{ std::pair{
"sha256-base16", "sha512",
hashString(HashAlgorithm::SHA256, "asdf"), hashString(HashAlgorithm::SHA256, "asdf"),
})); }));
// Failure tests for unsupported formats (base64, nix32, sri)
// These verify that non-base16 formats are rejected
INSTANTIATE_TEST_SUITE_P(
HashJSONParseFailure, HashJsonParseFailureTest, ::testing::Values("sha256-base64", "sha256-nix32"));
INSTANTIATE_TEST_SUITE_P(BLAKE3HashJSON, BLAKE3HashJsonTest, ([] { INSTANTIATE_TEST_SUITE_P(BLAKE3HashJSON, BLAKE3HashJsonTest, ([] {
ExperimentalFeatureSettings mockXpSettings; ExperimentalFeatureSettings mockXpSettings;
mockXpSettings.set("experimental-features", "blake3-hashes"); mockXpSettings.set("experimental-features", "blake3-hashes");
return ::testing::Values( return ::testing::Values(
std::pair{ std::pair{
"blake3-base16", "blake3",
hashString(HashAlgorithm::BLAKE3, "asdf", mockXpSettings), hashString(HashAlgorithm::BLAKE3, "asdf", mockXpSettings),
}); });
}())); }()));

View file

@ -164,7 +164,7 @@ static Hash parseLowLevel(
return res; return res;
} }
Hash Hash::parseSRI(std::string_view original) Hash Hash::parseSRI(std::string_view original, const ExperimentalFeatureSettings & xpSettings)
{ {
auto rest = original; auto rest = original;
@ -172,9 +172,9 @@ Hash Hash::parseSRI(std::string_view original)
auto hashRaw = splitPrefixTo(rest, '-'); auto hashRaw = splitPrefixTo(rest, '-');
if (!hashRaw) if (!hashRaw)
throw BadHash("hash '%s' is not SRI", original); throw BadHash("hash '%s' is not SRI", original);
HashAlgorithm parsedType = parseHashAlgo(*hashRaw); HashAlgorithm parsedType = parseHashAlgo(*hashRaw, xpSettings);
return parseLowLevel(rest, parsedType, {base64::decode, "SRI"}); return parseLowLevel(rest, parsedType, {base64::decode, "SRI"}, xpSettings);
} }
/** /**
@ -519,27 +519,13 @@ using namespace nix;
Hash adl_serializer<Hash>::from_json(const json & json, const ExperimentalFeatureSettings & xpSettings) Hash adl_serializer<Hash>::from_json(const json & json, const ExperimentalFeatureSettings & xpSettings)
{ {
auto & obj = getObject(json); auto & s = getString(json);
auto algo = parseHashAlgo(getString(valueAt(obj, "algorithm")), xpSettings); return Hash::parseSRI(s, xpSettings);
auto formatStr = getString(valueAt(obj, "format"));
auto format = parseHashFormat(formatStr);
// Only base16 format is supported for JSON serialization
if (format != HashFormat::Base16) {
throw Error("hash format '%s' is not supported in JSON; only 'base16' is currently supported", formatStr);
}
auto & hashS = getString(valueAt(obj, "hash"));
return Hash::parseExplicitFormatUnprefixed(hashS, algo, format, xpSettings);
} }
void adl_serializer<Hash>::to_json(json & json, const Hash & hash) void adl_serializer<Hash>::to_json(json & json, const Hash & hash)
{ {
json = { json = hash.to_string(HashFormat::SRI, true);
{"format", printHashFormat(HashFormat::Base16)},
{"algorithm", printHashAlgo(hash.algo)},
{"hash", hash.to_string(HashFormat::Base16, false)},
};
} }
} // namespace nlohmann } // namespace nlohmann

View file

@ -110,7 +110,8 @@ struct Hash
HashFormat explicitFormat, HashFormat explicitFormat,
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
static Hash parseSRI(std::string_view original); static Hash
parseSRI(std::string_view original, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
public: public:
/** /**

View file

@ -17,11 +17,7 @@ nix-build fixed.nix -A bad --no-out-link && fail "should fail"
nix path-info --json --json-format 2 "$path" | jq -e \ nix path-info --json --json-format 2 "$path" | jq -e \
'.info.[].ca == { '.info.[].ca == {
method: "flat", method: "flat",
hash: { hash: "md5-jd2L5LF5pSmvpfL/rkuYWA=="
algorithm: "md5",
format: "base16",
hash: "8ddd8be4b179a529afa5f2ffae4b9858"
},
}' }'
echo 'testing good...' echo 'testing good...'

View file

@ -47,16 +47,15 @@ try2 () {
hashFromGit=$(git -C "$repo" rev-parse "HEAD:$hashPath") hashFromGit=$(git -C "$repo" rev-parse "HEAD:$hashPath")
[[ "$hashFromGit" == "$expected" ]] [[ "$hashFromGit" == "$expected" ]]
# Convert base16 hash to SRI format for comparison
local hashSRI
hashSRI=$(nix hash convert --from base16 --to sri --hash-algo "$hashAlgo" "$hashFromGit")
nix path-info --json --json-format 2 "$path" | jq -e \ nix path-info --json --json-format 2 "$path" | jq -e \
--arg algo "$hashAlgo" \ --arg hashSRI "$hashSRI" \
--arg hash "$hashFromGit" \
'.info.[].ca == { '.info.[].ca == {
method: "git", method: "git",
hash: { hash: $hashSRI
algorithm: $algo,
format: "base16",
hash: $hash
},
}' }'
} }

View file

@ -30,7 +30,7 @@ path1_stuff=$(echo "$json" | jq -r .[].outputs.stuff)
[[ $(< "$path1"/n) = 0 ]] [[ $(< "$path1"/n) = 0 ]]
[[ $(< "$path1_stuff"/bla) = 0 ]] [[ $(< "$path1_stuff"/bla) = 0 ]]
nix path-info --json --json-format 2 "$path1" | jq -e '.info.[].ca | .method == "nar" and .hash.algorithm == "sha256"' nix path-info --json --json-format 2 "$path1" | jq -e '.info.[].ca | .method == "nar" and (.hash | startswith("sha256-"))'
path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | jq -r .[].outputs.out) path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | jq -r .[].outputs.out)
[[ $(< "$path2"/n) = 1 ]] [[ $(< "$path2"/n) = 1 ]]

View file

@ -166,7 +166,7 @@ printf 4.0 > "$flake1Dir"/version
printf Utrecht > "$flake1Dir"/who printf Utrecht > "$flake1Dir"/who
nix profile add "$flake1Dir" nix profile add "$flake1Dir"
[[ $("$TEST_HOME"/.nix-profile/bin/hello) = "Hello Utrecht" ]] [[ $("$TEST_HOME"/.nix-profile/bin/hello) = "Hello Utrecht" ]]
nix path-info --json --json-format 2 "$(realpath "$TEST_HOME"/.nix-profile/bin/hello)" | jq -e '.info.[].ca | .method == "nar" and .hash.algorithm == "sha256"' nix path-info --json --json-format 2 "$(realpath "$TEST_HOME"/.nix-profile/bin/hello)" | jq -e '.info.[].ca | .method == "nar" and (.hash | startswith("sha256-"))'
# Override the outputs. # Override the outputs.
nix profile remove simple flake1 nix profile remove simple flake1

View file

@ -20,16 +20,8 @@ diff --unified --color=always \
jq --sort-keys '.info | map_values(.narHash)') \ jq --sort-keys '.info | map_values(.narHash)') \
<(jq --sort-keys <<-EOF <(jq --sort-keys <<-EOF
{ {
"$fooBase": { "$fooBase": "sha256-QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA=",
"algorithm": "sha256", "$barBase": "sha256-9fhYGu9fqxcQC2Kc81qh2RMo1QcLBUBo8U+pPn+jthQ=",
"format": "base16",
"hash": "42fb4031b525feebe2f8b08e6e6a8e86f34e6a91dd036ada888e311b9cc8e690"
},
"$barBase": {
"algorithm": "sha256",
"format": "base16",
"hash": "f5f8581aef5fab17100b629cf35aa1d91328d5070b054068f14fa93e7fa3b614"
},
"$bazBase": null "$bazBase": null
} }
EOF EOF

View file

@ -58,7 +58,7 @@ nix store verify -r "$outPath2" --sigs-needed 1 --trusted-public-keys "$pk1"
# Build something content-addressed. # Build something content-addressed.
outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link) outPathCA=$(IMPURE_VAR1=foo IMPURE_VAR2=bar nix-build ./fixed.nix -A good.0 --no-out-link)
nix path-info --json --json-format 2 "$outPathCA" | jq -e '.info.[].ca | .method == "flat" and .hash.algorithm == "md5"' nix path-info --json --json-format 2 "$outPathCA" | jq -e '.info.[].ca | .method == "flat" and (.hash | startswith("md5-"))'
# Content-addressed paths don't need signatures, so they verify # Content-addressed paths don't need signatures, so they verify
# regardless of --sigs-needed. # regardless of --sigs-needed.

View file

@ -120,9 +120,8 @@
# Get the NAR hash of the unpacked tarball in SRI format # Get the NAR hash of the unpacked tarball in SRI format
path_info_json = substituter.succeed(f"nix path-info --json-format 2 --json {tarball_store_path}").strip() path_info_json = substituter.succeed(f"nix path-info --json-format 2 --json {tarball_store_path}").strip()
path_info_dict = json.loads(path_info_json)["info"] path_info_dict = json.loads(path_info_json)["info"]
narHash_obj = path_info_dict[os.path.basename(tarball_store_path)]["narHash"] # narHash is already in SRI format
# Convert from structured format {"algorithm": "sha256", "format": "base16", "hash": "..."} to SRI string tarball_hash_sri = path_info_dict[os.path.basename(tarball_store_path)]["narHash"]
tarball_hash_sri = substituter.succeed(f"nix hash convert --to sri {narHash_obj['algorithm']}:{narHash_obj['hash']}").strip()
print(f"Tarball NAR hash (SRI): {tarball_hash_sri}") print(f"Tarball NAR hash (SRI): {tarball_hash_sri}")
# Also get the old format hash for fetchTarball (which uses sha256 parameter) # Also get the old format hash for fetchTarball (which uses sha256 parameter)