| author | |
| committer | |
| log | de43f5eb6ae4a569efe15e3469b3de76a86d9cd1 |
| tree | dca7d9277507de70c93ec5f7fc95425995231e59 |
| parent | 67904e925d2b33c48dda3d4ddaf158328964dc2e |
7 files changed, 38 insertions(+), 38 deletions(-)
build.zig.zon+1-1| ... | ... | @@ -12,5 +12,5 @@ |
| 12 | 12 | }, |
| 13 | 13 | }, |
| 14 | 14 | .paths = .{""}, |
| 15 | .nonce = 0xc1ce108124179e16, | |
| 15 | .fingerprint = 0xc1ce108124179e16, | |
| 16 | 16 | } |
doc/build.zig.zon.md+5-5| ... | ... | @@ -22,24 +22,24 @@ Zig package namespace. |
| 22 | 22 | |
| 23 | 23 | Must be a valid bare Zig identifier (don't `@` me), limited to 32 bytes. |
| 24 | 24 | |
| 25 | Together with `nonce`, this represents a globally unique package identifier. | |
| 25 | Together with `fingerprint`, this represents a globally unique package identifier. | |
| 26 | 26 | |
| 27 | ### `nonce` | |
| 27 | ### `fingerprint` | |
| 28 | 28 | |
| 29 | 29 | Together with `name`, this represents a globally unique package identifier. This |
| 30 | 30 | field is auto-initialized by the toolchain when the package is first created, |
| 31 | 31 | and then *never changes*. This allows Zig to unambiguously detect when one |
| 32 | 32 | package is an updated version of another. |
| 33 | 33 | |
| 34 | When forking a Zig project, this nonce should be regenerated if the upstream | |
| 34 | When forking a Zig project, this fingerprint should be regenerated if the upstream | |
| 35 | 35 | project is still maintained. Otherwise, the fork is *hostile*, attempting to |
| 36 | take control over the original project's identity. The nonce can be regenerated | |
| 36 | take control over the original project's identity. The fingerprint can be regenerated | |
| 37 | 37 | by deleting the field and running `zig build`. |
| 38 | 38 | |
| 39 | 39 | This 64-bit integer is the combination of a 32-bit id component and a 32-bit |
| 40 | 40 | checksum. |
| 41 | 41 | |
| 42 | The id component within the nonce has these restrictions: | |
| 42 | The id component within the fingerprint has these restrictions: | |
| 43 | 43 | |
| 44 | 44 | `0x00000000` is reserved for legacy packages. |
| 45 | 45 |
lib/init/build.zig.zon+1-1| ... | ... | @@ -24,7 +24,7 @@ |
| 24 | 24 | // original project's identity. Thus it is recommended to leave the comment |
| 25 | 25 | // on the following line intact, so that it shows up in code reviews that |
| 26 | 26 | // modify the field. |
| 27 | .nonce = .NONCE, // Changing this has security and trust implications. | |
| 27 | .fingerprint = .FINGERPRINT, // Changing this has security and trust implications. | |
| 28 | 28 | |
| 29 | 29 | // Tracks the earliest Zig version that the package considers to be a |
| 30 | 30 | // supported use case. |
src/Package.zig+4-4| ... | ... | @@ -10,25 +10,25 @@ pub const multihash_len = 1 + 1 + Hash.Algo.digest_length; |
| 10 | 10 | pub const multihash_hex_digest_len = 2 * multihash_len; |
| 11 | 11 | pub const MultiHashHexDigest = [multihash_hex_digest_len]u8; |
| 12 | 12 | |
| 13 | pub const Nonce = packed struct(u64) { | |
| 13 | pub const Fingerprint = packed struct(u64) { | |
| 14 | 14 | id: u32, |
| 15 | 15 | checksum: u32, |
| 16 | 16 | |
| 17 | pub fn generate(name: []const u8) Nonce { | |
| 17 | pub fn generate(name: []const u8) Fingerprint { | |
| 18 | 18 | return .{ |
| 19 | 19 | .id = std.crypto.random.intRangeLessThan(u32, 1, 0xffffffff), |
| 20 | 20 | .checksum = std.hash.Crc32.hash(name), |
| 21 | 21 | }; |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | pub fn validate(n: Nonce, name: []const u8) bool { | |
| 24 | pub fn validate(n: Fingerprint, name: []const u8) bool { | |
| 25 | 25 | switch (n.id) { |
| 26 | 26 | 0x00000000, 0xffffffff => return false, |
| 27 | 27 | else => return std.hash.Crc32.hash(name) == n.checksum, |
| 28 | 28 | } |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | pub fn int(n: Nonce) u64 { | |
| 31 | pub fn int(n: Fingerprint) u64 { | |
| 32 | 32 | return @bitCast(n); |
| 33 | 33 | } |
| 34 | 34 | }; |
src/Package/Fetch.zig+4-4| ... | ... | @@ -44,7 +44,7 @@ omit_missing_hash_error: bool, |
| 44 | 44 | /// which specifies inclusion rules. This is intended to be true for the first |
| 45 | 45 | /// fetch task and false for the recursive dependencies. |
| 46 | 46 | allow_missing_paths_field: bool, |
| 47 | allow_missing_nonce: bool, | |
| 47 | allow_missing_fingerprint: bool, | |
| 48 | 48 | allow_name_string: bool, |
| 49 | 49 | /// If true and URL points to a Git repository, will use the latest commit. |
| 50 | 50 | use_latest_commit: bool, |
| ... | ... | @@ -649,7 +649,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void { |
| 649 | 649 | |
| 650 | 650 | f.manifest = try Manifest.parse(arena, ast.*, .{ |
| 651 | 651 | .allow_missing_paths_field = f.allow_missing_paths_field, |
| 652 | .allow_missing_nonce = f.allow_missing_nonce, | |
| 652 | .allow_missing_fingerprint = f.allow_missing_fingerprint, | |
| 653 | 653 | .allow_name_string = f.allow_name_string, |
| 654 | 654 | }); |
| 655 | 655 | const manifest = &f.manifest.?; |
| ... | ... | @@ -752,7 +752,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void { |
| 752 | 752 | .job_queue = f.job_queue, |
| 753 | 753 | .omit_missing_hash_error = false, |
| 754 | 754 | .allow_missing_paths_field = true, |
| 755 | .allow_missing_nonce = true, | |
| 755 | .allow_missing_fingerprint = true, | |
| 756 | 756 | .allow_name_string = true, |
| 757 | 757 | .use_latest_commit = false, |
| 758 | 758 | |
| ... | ... | @@ -2323,7 +2323,7 @@ const TestFetchBuilder = struct { |
| 2323 | 2323 | .job_queue = &self.job_queue, |
| 2324 | 2324 | .omit_missing_hash_error = true, |
| 2325 | 2325 | .allow_missing_paths_field = false, |
| 2326 | .allow_missing_nonce = true, // so we can keep using the old testdata .tar.gz | |
| 2326 | .allow_missing_fingerprint = true, // so we can keep using the old testdata .tar.gz | |
| 2327 | 2327 | .allow_name_string = true, // so we can keep using the old testdata .tar.gz |
| 2328 | 2328 | .use_latest_commit = true, |
| 2329 | 2329 |
src/Package/Manifest.zig+13-13| ... | ... | @@ -52,7 +52,7 @@ pub const ParseOptions = struct { |
| 52 | 52 | /// Deprecated, to be removed after 0.14.0 is tagged. |
| 53 | 53 | allow_name_string: bool = true, |
| 54 | 54 | /// Deprecated, to be removed after 0.14.0 is tagged. |
| 55 | allow_missing_nonce: bool = true, | |
| 55 | allow_missing_fingerprint: bool = true, | |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | 58 | pub const Error = Allocator.Error; |
| ... | ... | @@ -81,7 +81,7 @@ pub fn parse(gpa: Allocator, ast: Ast, options: ParseOptions) Error!Manifest { |
| 81 | 81 | .paths = .{}, |
| 82 | 82 | .allow_missing_paths_field = options.allow_missing_paths_field, |
| 83 | 83 | .allow_name_string = options.allow_name_string, |
| 84 | .allow_missing_nonce = options.allow_missing_nonce, | |
| 84 | .allow_missing_fingerprint = options.allow_missing_fingerprint, | |
| 85 | 85 | .minimum_zig_version = null, |
| 86 | 86 | .buf = .{}, |
| 87 | 87 | }; |
| ... | ... | @@ -157,7 +157,7 @@ const Parse = struct { |
| 157 | 157 | paths: std.StringArrayHashMapUnmanaged(void), |
| 158 | 158 | allow_missing_paths_field: bool, |
| 159 | 159 | allow_name_string: bool, |
| 160 | allow_missing_nonce: bool, | |
| 160 | allow_missing_fingerprint: bool, | |
| 161 | 161 | minimum_zig_version: ?std.SemanticVersion, |
| 162 | 162 | |
| 163 | 163 | const InnerError = error{ ParseFailure, OutOfMemory }; |
| ... | ... | @@ -175,7 +175,7 @@ const Parse = struct { |
| 175 | 175 | var have_name = false; |
| 176 | 176 | var have_version = false; |
| 177 | 177 | var have_included_paths = false; |
| 178 | var nonce: ?Package.Nonce = null; | |
| 178 | var fingerprint: ?Package.Fingerprint = null; | |
| 179 | 179 | |
| 180 | 180 | for (struct_init.ast.fields) |field_init| { |
| 181 | 181 | const name_token = ast.firstToken(field_init) - 2; |
| ... | ... | @@ -192,8 +192,8 @@ const Parse = struct { |
| 192 | 192 | } else if (mem.eql(u8, field_name, "name")) { |
| 193 | 193 | p.name = try parseName(p, field_init); |
| 194 | 194 | have_name = true; |
| 195 | } else if (mem.eql(u8, field_name, "nonce")) { | |
| 196 | nonce = try parseNonce(p, field_init); | |
| 195 | } else if (mem.eql(u8, field_name, "fingerprint")) { | |
| 196 | fingerprint = try parseFingerprint(p, field_init); | |
| 197 | 197 | } else if (mem.eql(u8, field_name, "version")) { |
| 198 | 198 | p.version_node = field_init; |
| 199 | 199 | const version_text = try parseString(p, field_init); |
| ... | ... | @@ -220,16 +220,16 @@ const Parse = struct { |
| 220 | 220 | if (!have_name) { |
| 221 | 221 | try appendError(p, main_token, "missing top-level 'name' field", .{}); |
| 222 | 222 | } else { |
| 223 | if (nonce) |n| { | |
| 223 | if (fingerprint) |n| { | |
| 224 | 224 | if (!n.validate(p.name)) { |
| 225 | return fail(p, main_token, "invalid nonce: 0x{x}; if this is a new or forked package, use this value: 0x{x}", .{ | |
| 226 | n.int(), Package.Nonce.generate(p.name).int(), | |
| 225 | return fail(p, main_token, "invalid fingerprint: 0x{x}; if this is a new or forked package, use this value: 0x{x}", .{ | |
| 226 | n.int(), Package.Fingerprint.generate(p.name).int(), | |
| 227 | 227 | }); |
| 228 | 228 | } |
| 229 | 229 | p.id = n.id; |
| 230 | } else if (!p.allow_missing_nonce) { | |
| 231 | try appendError(p, main_token, "missing top-level 'nonce' field; suggested value: 0x{x}", .{ | |
| 232 | Package.Nonce.generate(p.name).int(), | |
| 230 | } else if (!p.allow_missing_fingerprint) { | |
| 231 | try appendError(p, main_token, "missing top-level 'fingerprint' field; suggested value: 0x{x}", .{ | |
| 232 | Package.Fingerprint.generate(p.name).int(), | |
| 233 | 233 | }); |
| 234 | 234 | } else { |
| 235 | 235 | p.id = 0; |
| ... | ... | @@ -385,7 +385,7 @@ const Parse = struct { |
| 385 | 385 | } |
| 386 | 386 | } |
| 387 | 387 | |
| 388 | fn parseNonce(p: *Parse, node: Ast.Node.Index) !Package.Nonce { | |
| 388 | fn parseFingerprint(p: *Parse, node: Ast.Node.Index) !Package.Fingerprint { | |
| 389 | 389 | const ast = p.ast; |
| 390 | 390 | const node_tags = ast.nodes.items(.tag); |
| 391 | 391 | const main_tokens = ast.nodes.items(.main_token); |
src/main.zig+10-10| ... | ... | @@ -4752,10 +4752,10 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4752 | 4752 | }; |
| 4753 | 4753 | var ok_count: usize = 0; |
| 4754 | 4754 | |
| 4755 | const nonce: Package.Nonce = .generate(sanitized_root_name); | |
| 4755 | const fingerprint: Package.Fingerprint = .generate(sanitized_root_name); | |
| 4756 | 4756 | |
| 4757 | 4757 | for (template_paths) |template_path| { |
| 4758 | if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, nonce)) |_| { | |
| 4758 | if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| { | |
| 4759 | 4759 | std.log.info("created {s}", .{template_path}); |
| 4760 | 4760 | ok_count += 1; |
| 4761 | 4761 | } else |err| switch (err) { |
| ... | ... | @@ -5225,7 +5225,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 5225 | 5225 | .job_queue = &job_queue, |
| 5226 | 5226 | .omit_missing_hash_error = true, |
| 5227 | 5227 | .allow_missing_paths_field = false, |
| 5228 | .allow_missing_nonce = false, | |
| 5228 | .allow_missing_fingerprint = false, | |
| 5229 | 5229 | .allow_name_string = false, |
| 5230 | 5230 | .use_latest_commit = false, |
| 5231 | 5231 | |
| ... | ... | @@ -7127,7 +7127,7 @@ fn cmdFetch( |
| 7127 | 7127 | .job_queue = &job_queue, |
| 7128 | 7128 | .omit_missing_hash_error = true, |
| 7129 | 7129 | .allow_missing_paths_field = false, |
| 7130 | .allow_missing_nonce = true, | |
| 7130 | .allow_missing_fingerprint = true, | |
| 7131 | 7131 | .allow_name_string = true, |
| 7132 | 7132 | .use_latest_commit = true, |
| 7133 | 7133 | |
| ... | ... | @@ -7468,10 +7468,10 @@ fn loadManifest( |
| 7468 | 7468 | 0, |
| 7469 | 7469 | ) catch |err| switch (err) { |
| 7470 | 7470 | error.FileNotFound => { |
| 7471 | const nonce: Package.Nonce = .generate(options.root_name); | |
| 7471 | const fingerprint: Package.Fingerprint = .generate(options.root_name); | |
| 7472 | 7472 | var templates = findTemplates(gpa, arena); |
| 7473 | 7473 | defer templates.deinit(); |
| 7474 | templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, nonce) catch |e| { | |
| 7474 | templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| { | |
| 7475 | 7475 | fatal("unable to write {s}: {s}", .{ |
| 7476 | 7476 | Package.Manifest.basename, @errorName(e), |
| 7477 | 7477 | }); |
| ... | ... | @@ -7529,7 +7529,7 @@ const Templates = struct { |
| 7529 | 7529 | out_dir: fs.Dir, |
| 7530 | 7530 | root_name: []const u8, |
| 7531 | 7531 | template_path: []const u8, |
| 7532 | nonce: Package.Nonce, | |
| 7532 | fingerprint: Package.Fingerprint, | |
| 7533 | 7533 | ) !void { |
| 7534 | 7534 | if (fs.path.dirname(template_path)) |dirname| { |
| 7535 | 7535 | out_dir.makePath(dirname) catch |err| { |
| ... | ... | @@ -7555,9 +7555,9 @@ const Templates = struct { |
| 7555 | 7555 | try templates.buffer.appendSlice(root_name); |
| 7556 | 7556 | i += ".NAME".len; |
| 7557 | 7557 | continue; |
| 7558 | } else if (std.mem.startsWith(u8, contents[i..], ".NONCE")) { | |
| 7559 | try templates.buffer.writer().print("0x{x}", .{nonce.int()}); | |
| 7560 | i += ".NONCE".len; | |
| 7558 | } else if (std.mem.startsWith(u8, contents[i..], ".FINGERPRINT")) { | |
| 7559 | try templates.buffer.writer().print("0x{x}", .{fingerprint.int()}); | |
| 7560 | i += ".FINGERPRINT".len; | |
| 7561 | 7561 | continue; |
| 7562 | 7562 | } else if (std.mem.startsWith(u8, contents[i..], ".ZIGVER")) { |
| 7563 | 7563 | try templates.buffer.appendSlice(build_options.version); |