I don't think this will be solved until there is a radical rethinking of package managers, build systems, and programming languages.
Like the founder of socket.dev, I think that static analysis will play a role. However, I don't agree that that's the entire answer.
The static analysis has to be in the programming language used in the build. The language must have fine-grained permissions built into it, and those permissions should be able to be used both at compile time and runtime.
The build system should take advantage of the programming language's fine-grained permissions to allow the user building the software to restrict what the software can do at build time. It should be possible to decide, for example, that the build can only access files in a particular directory, and if that is violated, the build system will error. Same thing with network access.
The package manager should take advantage of the build system to build all software from source as far as possible, and to ensure that the package uses the build system and programming language to ensure the package cannot stomp on the user's computer at build time.
That is the minimum before these issues have any hope of being resolved.
But I still think that is not enough.
Say you have a dependency that you do not trust. If you could compile it into a form that could be interpreted by the same interpreter that the programming language mentioned above uses to enforce permissions at runtime, and if that interpreter had a way to transfer data to and from the code it was running, then you could have a system where you embed the interpreter in your code and use it to run your untrusted dependency. Then the untrusted dependency can be properly sandboxed.
Yes, you'll pay in performance, but you won't pay whatever you might pay if a dependency goes rogue.
That is the only way to "fix" these supply-chain issues until everyone actually vets their dependencies.
Disclaimer: yes, I'm working on a language, build system, and package manager with the above features.
> It should be possible to decide, for example, that the build can only access files in a particular directory, and if that is violated, the build system will error.
(How) does that work for dynamic file access? I.e. the files are often not known at build time.
I don't know if my current design is good, so it is subject to change.
The current design is to allow the user to give the interpreter a predicate (function that returns a Boolean) to run whenever something asks for access to a file. It would return true for allowing access, false otherwise, and its arguments would include what package (module, library, etc.) is asking for access, what kind of access, and exactly what file it's being asked for. The predicate can do all sorts of wild and wonderful things to figure out if the package should be allowed access. It could even pop up a dialog box for the user in the cases it can't figure out, which would also have the benefit of alerting the user that there's a package that might have gone rogue. In fact, in those cases where it denies access, it can still alert the user, who can then do something about it.
I like this design (so far), and I think it's best because if you're going to enforce runtime permissions, you need runtime abilities to make judgments. It can't be a simple static list of files, as you rightly figured out, although it could use such static lists for the easy cases.
Like the founder of socket.dev, I think that static analysis will play a role. However, I don't agree that that's the entire answer.
The static analysis has to be in the programming language used in the build. The language must have fine-grained permissions built into it, and those permissions should be able to be used both at compile time and runtime.
The build system should take advantage of the programming language's fine-grained permissions to allow the user building the software to restrict what the software can do at build time. It should be possible to decide, for example, that the build can only access files in a particular directory, and if that is violated, the build system will error. Same thing with network access.
The package manager should take advantage of the build system to build all software from source as far as possible, and to ensure that the package uses the build system and programming language to ensure the package cannot stomp on the user's computer at build time.
That is the minimum before these issues have any hope of being resolved.
But I still think that is not enough.
Say you have a dependency that you do not trust. If you could compile it into a form that could be interpreted by the same interpreter that the programming language mentioned above uses to enforce permissions at runtime, and if that interpreter had a way to transfer data to and from the code it was running, then you could have a system where you embed the interpreter in your code and use it to run your untrusted dependency. Then the untrusted dependency can be properly sandboxed.
Yes, you'll pay in performance, but you won't pay whatever you might pay if a dependency goes rogue.
That is the only way to "fix" these supply-chain issues until everyone actually vets their dependencies.
Disclaimer: yes, I'm working on a language, build system, and package manager with the above features.