-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support relative paths in package manager #14603
Conversation
Apologies, I'm not that familiar with Zig(so take the following question with that caveat). Is this prone to a path traversal attack? If I clone a git repo that has a |
relative paths are not URIs, i believe it is inappropriate to add this special casing to std.Uri |
This type of functionality is useful for projects like https://github.com/SerenityOS/serenity. In that single project tree are ~60+ libraries and ~80+ applications all with dependencies on each other i.e. appA -> libA -> libB. Needing hashes, references to archive files or needing absolute paths (how can that work on my machine and yours?) flies in the face of developing multiple things in a single source tree. |
@leecannon i am not saying relative paths should not be supported, i am saying that std.Uri is not the place to implement that support. additionally, this PR does nothing about the onerous hash requirement. |
I agree that parsing relative paths inside std.Uri is a bit weird. It does make the subsequent logic a bit easier, since we don't need to handle a special case for relative paths, since absolute paths are already a valid URI scheme. Regarding the hash requirement, my opinion is that it is important to ensure that the hashes referenced in |
Paths are now a possible field for dependencies inside .{
.name = "base",
.version = "0.0.0",
.dependencies = .{
.dep = .{
.path = "/home/adam/dep/",
// alternatively, .url = "file:///home/adam/dep/",
.hash = "1220ebfc0074d94ecdab83cef08dae264eeb0c8ae6ee9734fd9bcd3fe83a6236e8a1",
},
},
} .{
.name = "dep",
.version = "0.0.0",
.dependencies = .{
.dep2 = .{
.path = "dep2",
.hash = "1220abdec7efb3042b27db55066eae97088b527be45ab7dda0fe706d6a6f64d3cf60",
}
}
} This removes the special casing inside |
This depends on the permissions the zig compiler is running with. For example, if I run |
Yeah, you can right now try to access system files like |
this discussion should take place on #14339.
|
I will have a look soon. |
If there are issues with recursion and directory trees, it would be good to at least allow file:/// access to archive files (.tar.gz, .tgz, .bgz, etc.) which shouldn't allow people to escape sandboxing. |
Can we get this pulled into the main branch? Given all the changes in the build system, it really needs to get pulled in so people can start trying it out. |
Sorry, not until I look at it. The timing is a bit unfortunate since I was focusing on the build-parallel branch and now I am having a much needed vacation. Please be patient. |
Take your time. I don’t want this merged until it’s been reviewed either. We appreciate all the work you’ve been doing, and you deserve a break. |
Understandable. I tried to pull the fork to try it out, but I clearly just don't understand the build.zig.zon stuff clearly enough to provide credible feedback. :( |
As a solution to the last bullet point in the OP, does it make sense to have a switch to ignore the hash check when referencing a directory (either absolute or relative) when building? I can see the hash check being important for people that vendor their dependencies, but for someone working in a monorepo style (as noted) it can become a hassle quickly. I can't think of a reason to have the same switch for tarball/remote packages, but I digress. EDIT: just realized I regurgitated #14339 (comment) |
At this point, we need to get something into people's hands so everybody can start iterating on it. It's not going to be perfectly correct, that's fine. But this is currently holding up the possibility of exploring the space as well as people sending in patches to make things work better as well as people writing tutorials about it. |
Any plans to merge this pull request into master? I've tried to compile Zig with this patch to no avail and quite some trouble as well - it would be nice to have this be merged into master and for an official Zig build to be provided that supports this very-well needed feature. Thanks in advance (the conflicts should also be resolved, too). |
I should have a chance to resolve the conflicts this coming week (currently traveling). It still needs review before it can be merged, hopefully now that intern pool is landed and SYCL is over, the core team will have some more time. |
@AdamGoertz how;'s everything coming along? |
The CI seemingly is failing on Windows regarding the usage of |
The Windows release workflow failed with a weird AccessDenied error. Perhaps rerun that workflow? |
d39cc1c
to
7d279c9
Compare
Did this get integrated? It really needs to be in 0.11 so people can start banging on it ... |
I'm old rust dev but new here. |
1cc26fc
to
48e95b9
Compare
@getcisher Probably best not to use this PR to discuss higher-level Zig decisions like this. But if you wanna read more, issue #14290 and the linked PR #14265 document some of this decision process. |
551628a
to
af1e5bf
Compare
src/Package.zig
Outdated
/// The absolute path to a file or directory. | ||
/// This may be a file that requires unpacking (such as a .tar.gz), | ||
/// or the path to the root directory of a package. | ||
file: []const u8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolute paths are not portable, please avoid absolute paths entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolute paths have been squashed 👍
src/Package.zig
Outdated
/// Make a OS-specific file system path | ||
/// This performs the inverse operation of normalizePath, | ||
/// converting forward slashes into backslashes on Windows | ||
fn unnormalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 { | ||
const canonical_sep = '/'; | ||
|
||
const unnormalized = try arena.dupe(u8, fs_path); | ||
if (fs.path.sep == canonical_sep) | ||
return unnormalized; | ||
|
||
for (unnormalized) |*byte| { | ||
switch (byte.*) { | ||
canonical_sep => byte.* = fs.path.sep, | ||
else => continue, | ||
} | ||
} | ||
return unnormalized; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this function should be used. Why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The question here is whether we want relative paths to have a consistent path separator across platforms or not. Do windows users need to write all of their paths as ‘path\to\some\package’ while non-windows users write ‘path/to/some/package’? This will make dependency paths platform-dependent. Unless there’s some other way this is handled already that I’m not aware of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think forward slashes should always be used in build.zig.zon files. What happens if you don't call this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. On windows, this function converts forward slashes (from build.zig.zon) to backslashes (for opening the file).
If you don’t call this function, the file will fail to open on windows because the path will be invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how that can be the case, since Windows supports forward slashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, is that the case? I thought I encountered this issue during my original tests on windows, but I can double check and remove this if it’s not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsurprisingly, you are correct. Must have been something absolute path or URI related that I was remembering. Regardless, unnecessary path modifications have been eliminated.
70dfa9a
to
38a22b0
Compare
I appreciate the conflict fix but, don't worry, you can just let this sit on green and I'll take care of the merge 👍 (I'm going to rebase it so I have to redo the conflict fix anyway) |
Ok, sounds good, I’ll let you handle it. Thanks! |
Nice work, thank you for being patient with the long review process on this one. I think we landed somewhere much better than originally planned. I've done a more thorough review and built the changes locally and ran a few tests, and I think I'm ready to call this good enough to take for a spin in master branch. However, I want to discuss briefly what's going on with populating the Dependency.hash field based on a hash of the (absolute?) file path. This seems a bit strange to me since there is no hash, and populating the field in this way is mutating something that I think should be immutable (the inputs from the build manifest file). On the other hand, I see that in So, I think I'm fine with merging this, and merging a few more contributions to the package manager code, why not, and then I'll need to do a deep dive and audit all the package management code and likely do some reworking to make this stuff coherent. That's fine, that's my job here anyway. It'll be a bit of a roundabout way to get there, but eventually we'll end up with something that continues to solve everyone's use cases, and also is more maintainable and ready for some of the more advanced toolchain features that are planned. |
This commit makes the following changes: * Disallow file:/// URIs * Allow only relative paths in the .path field of build.zig.zon * Remote now-unneeded shlwapi dependency
No need to create paths with windows-specific path separators
In addition to improving readability, this also fixes a subtle bug where the Progress node could display the wrong total number of packages to fetch.
I had been checking up on this PR on and off, and missed when absolute paths were dropped, but I'll point out that if packages can only reference each other by relative paths, then on Windows, packages on different drive letters (C:, D:, etc…) are pretty much inaccessible to each other. Granted, I think this might be a fairly narrow edge case, but maybe still something to keep in mind, given I'm sure there's probably someone out there that likes keeping all their code organized across 5+ different drives. |
So, what is the mechanism for fetching from a local git repository if we don't have any absolute paths? There seems to have been a bifurcation of "path" and "url" and what their purposes are. I would really like to have some way to access "file://some/local/path/gitarchive.tgz" short of standing up a full blown http server just to get to "http://localhost/some/local/path/gitarchive.tgz". ie. "url" is effectively always an absolute path anyway so it being able to do that with "file:" instead of "http:" really isn't much of a shift. |
Can you explain more this use case where you want to hard-code paths to tarballs on your own file system? How would you coordinate working on your own project on different computers, or collaborate with someone else? |
By having a known root? And then either installing stuff into that root via replication or network mount? It is not at all uncommon to have something like "C:\sdks" on Windows and "/home/sdks" on Linux/OS X and then reference everything off of them for embedded development. And, if you get a particularly annoying vendor, they will build chunks of the library assuming that root exists and reference everything to it. And, while I said embedded, even projects like Java and Vulkan do things like this and define an SDK root. So, it doesn't seem to be limited to sprawling embedded projects like Zephyr. I know some of this discussion hovers around security. However, I'd like to assert something to challenge one of the baseline assumptions: making people stand up a web server/repo server to access a filesystem local repository actually decreases security WAY more than giving people a way to access the file system from a build file. Local access means you can only do what the user can do. However, forcing a random end-user to stand up a web server almost always results in something that can turn into a remote exploit. An end user will invariably do the easiest thing--not the safest. I would like to have actual filesystem access, but, barring that, at the very least the ability to let the package manager pull in a verifiable "archive file" from Git, Mercurial, etc. on the local filesystem is a sufficient workaround (it can be checked, it can be hashed, it can be signed, etc.). Side note: I also have strong opinions about how forcing people through this kind of hoop entrenches and privileges the "centralized access model" (GitHub, GitLab, etc.) rather than encouraging a "federated model", but that's a complicated discussion that should be had in person over alcoholic beverages. |
One use case would be rewriting the URLs in a nix derivation so you can smoothly integrate zig packages into the nix ecosystem, where the paths are the same on each machine |
@andrewrk FWIW, I am using zig build in a way where I think absolute paths would be beneficial. The use case is as the low-level build system of the Acton programming language. The Acton compiler generates C code (one day we'll generate zig code instead 😄) which is then compiled with zig to libraries & executable binaries. The zig build is invoked at build time of Acton itself, like when we build stdlib of Acton we produce a .a library and ship in the Acton distribution so it can be quickly linked in with Acton programs when the Acton user compiles their Acton program. However, the Acton distribution also ships with source code for e.g. stdlib which is used for cross-compilation or when using custom compilation options. Acton is normally installed in I recognize this is a very niche use case, so I'm fine with absolute paths not being supported, but at least I'd like to add a datapoint where I think absolute paths do make sense 😄 |
@plajjan can you open a new issue with this use case explanation? |
Closes #14339 and #14825.
This PR adds support in the package manager for fetching dependencies from relative paths. For example, a project with the following dependency structure successfully compiles:
base/build.zig.zon
:dep/build.zig.zon
:Other tests
These projects all build successfully
File dependencies can be provided using the new
.path
field. These paths can refer to either a directory containing abuild.zig
or to a file that the package manager is capable on unpacking, such as a.tar.gz
.In the case of a file that must be unpacked, such as a
.tar
, it is unpacked into the global cache in the same way as if the file was fetched from the internet. However, if the provided path points to a directory, no caching is performed and the build system instead references the files using the provided paths. Relative paths are resolved relative to thebuild.zig
of the package that declared the dependency.When a dependency references a directory, no hash field is required, and an error will be emitted if the user provides one.
Unlike the original issue which this PR addresses,
file:///
URIs are not allowed. For example, the followingbuild.zig.zon
produces an error:Absolute paths are also disallowed:
Let me know if you have any feedback or suggestions.