Submind YouTube summaries
Thumbnail for One Binary, Every Package Manager: Shipping a Rust CLI To PyPI, Npm, Homebrew, Winget… - A. Kumar

One Binary, Every Package Manager: Shipping a Rust CLI To PyPI, Npm, Homebrew, Winget… - A. Kumar

Watch on YouTube

Video summary

The speaker, Ajit Kumar, introduces himself as a software architect and Rust developer who faced significant challenges managing environment configuration files, specifically the `.env` format. He explains that while tools like Python's Django or JavaScript's Next.js rely heavily on these files for storing API keys and settings, the lack of a standard specification makes them fragile during deployment to cloud secret managers. To solve this, he developed EVNX, a Rust-based CLI tool designed to manage, version, and convert these configurations seamlessly across different environments. This project highlighted his transition from Python development to Rust, where he was attracted by Cargo's ability to handle the entire software lifecycle—from testing to publishing—within a single ecosystem, offering superior security and memory management compared to other languages. The core of the presentation focuses on the strategy of "one binary, every package manager," which allows developers to write code once in Rust and distribute it across diverse ecosystems without forcing users to install the Rust toolchain. By leveraging Rust's cross-compilation capabilities, the speaker builds a single source code that generates native binaries for various platforms like Linux, macOS, and Windows. These pre-compiled binaries are then wrapped using specific packaging formats for each ecosystem: Maturin is used to create Python wheels for PyPI, while NPM wrappers handle JavaScript environments by resolving the correct binary based on the user's system. This approach ensures that developers from different backgrounds can install and use the tool through their familiar package managers like `pip`, `npm`, or `npx` without needing to understand Rust compilation processes. The talk further details the specific integration methods for major distribution channels, including Homebrew and Windows Package Manager (Winget). For Homebrew, a simple Ruby formula is created to manage the installation of the binary on macOS and Linux, while Winget requires creating a manifest file that undergoes an automated security scanning process involving digital certificates to prevent false malware alerts. The speaker notes that while initial submissions to repositories like PyPI or NPM lack strict signature requirements, which poses supply chain risks, the long-term solution involves signing binaries with digital certificates to enhance trust and security. Additionally, he explores future applications such as GitHub Actions for pre-commit scanning and AI skills, demonstrating how the tool can integrate into automated workflows and assist AI agents in securing code repositories before pushes. In conclusion, the presentation emphasizes that while the initial setup of building binaries for multiple targets and configuring CI/CD pipelines requires effort, it is a one-time investment that pays off significantly in distribution reach. The speaker illustrates this by comparing download statistics, noting that targeting only Rust users would result in low adoption, whereas distributing via Python and JavaScript ecosystems increased downloads to thousands. By automating the release process across PyPI, NPM, Homebrew, Winget, and Docker, developers can achieve broad community adoption while maintaining a secure and efficient supply chain. The speaker encourages open-source contributions to both his configuration management project and the distribution tool, highlighting that once the infrastructure is established, releasing new versions becomes a fast and automated process for reaching a global developer audience.
Read the full video transcript
Good afternoon, everyone. So, yeah. So, I will be uh presenting uh one binary every package manager uh shipping a Rust CLI to uh PIP, NPM, and all. So, let's get it started. So, who am I? Uh I am uh Ajit Kumar, and I have done my PhD uh from Pondicherry University. Basically, I come from India. And I have been in Korea for last 6 year. I did my post doc from Sungkyunkwan University, and then uh from last 3 years, I have been working as a software developer. And my current role is uh in Belmatics, where I work as a senior software architect. So, my take a stakes are like I have been a Python developer, and then uh from last 2 years, I have been doing Rust web technology and all. So, I have interest on running, hiking, and of course, open source. And in uh Seoul, I am uh actively participating in uh Dev Korea, which is a English-based IT meetup. And then uh part of Seoul Rust. So, these two are run by Florin and Jan Wagner. So, these are the sources where I have been uh actively involved. If you want, you can connect uh with me there. So, what is my agenda? So, I have uh as you uh come to know about my brief introduction that I have been a IT developer not too long, just 3 years, but before that, I have been doing software for research and publications. So, then uh when I started my job, I got this .env file. Everyone who have been doing development, they will be knowing it exist uh still. And then uh how Rust development and distribution system work, and then what is problem with uh one binary, and then how different package manager work. So, like in previous talk, we come to know about uh uh supply chain of software. So, these packages many time uh you will have that they have malicious package and all. So, maybe that will solve the problem. And then what are the lesson learned and result. So, .env and .env's story. So, if you have been developer, you know that there is basically a traditionally we use a text file .env for storing our key and value pair. It can be anything for API key to database setup to configuration. But nowadays, with different software, now these things are evolving and we are going different way also. But uh still many of the package they use. So, it is used by Python like uh in Django or fast API, we use this. We also uh Next.js, most of uh front-end developer, Next.js, React, they also use it. And in this we keep all the API keys, environment configuration and all. But when we nowadays when we go for deployment, we have started using secret manager like in AWS and all other uh places also. So, when I started, there was information uh spread here and there. So, first I started collecting all the uh configuration and we have put into this .env space. So, it's tell about what it .env. There is no standard specification. Suppose in Docker, you can have uh spaces uh equal to after equal to. In some, you don't have like in in uh AWS, they don't allow to have a spaces. So, there is no specification. So, it's very difficult when you migrate from one uh package or any uh like if you are deploying your project to AWS and want to convert to secret manager, your .env start uh breaking. So, there was many problem. So, I started uh first learning about it, and then I put a place where anyone can contribute and add their information about what they know about .env file. >> [snorts] >> Then, over time, I started facing more problem. So, I thought to okay, let's build a tool uh that can help me to manage my .env file. So, .env .env is only one part. Then, we have started having .env.example, where you put all the dummy values, so other developer or if you are putting open source software, then other developer can know what are the keys and their value will be needed. So, then it become uh .env.example, and then if you have different uh environment, a staging, a release, and all, then you are started having .env.release.test, and all. So, then now from one .env, they are started uh many .env. And then at the end, when you go for suppose deployment to any cloud or anywhere, then maybe you decided to choose AWS secret manager. Then now you have to convert your .env to secret manager. So, again conversion. So, likewise, this evolved. So, this all was like being new to software development, this all was creating trouble for me. So, I thought okay, let's uh do something about it and I start a tool that can help me to manage this uh eventually. So, over time, that tool become EVNX. I wanted to have EVNX, but that name was taken with some other project. So, I started it as a EVNX, and now this is a tool that help you to manage .env. It help to have a setup with default variables. It help to manage different version. It also help to convert to different like if you want your .env to Docker complete uh to work with Docker, then you can convert. If you want to work with a secret manager, it helped to convert your ENB into those format also. So likewise, there is many feature, but this talk is not about ENBX work. It is about how we can distribute a simple CLI. If you want to distribute to different set of developer or you can say different set of community, then this talk is about how you can distribute your tool. >> [clears throat] >> So before I move why I started EVNX in Rust because I was trying to write a CLI. My options were Python and then if I have to do some low level, then I was thinking about C++. But I have been introduced to Rust recently. So I thought to give a go with the Rust and then it was very nice to work with Rust. I have very good experience using Cargo because it is integrated everything like your test, your publish, everything is all the tool chain. The as a developer you use Mac, you use for testing different tool in different Java or any other programming environment. In Rust, Cargo make all in one. So you don't have to jump from your a system to run one tool to another tool. With Cargo, you can do all the software life cycle for Rust project in one one place. So this was one of attracting point for me to work with Rust and Cargo. So I just It is my personal choice and then Rust language is also powerful for security and for memory usage and all. And I was building a CLI. So I thought okay, Rust will be a good choice. So that's that's how we are started in Rust. So as I mentioned, Rust development and distribution, either CLI or any big project is very simple. So let's have a brief outline how it's work. So sub- uh package manager is called crates. So, c r a t e s crates.io, that is Rust package manager. Like in Python, you have PIP. NPM, you have NPM. So, likewise, Rust have their own package manager. So, with Cargo's CLI, you can just do all the development, and you can also publish to the crate. So, if you are working on a binary project, maybe tool or something, you can publish. If you are working on a library, that also you can publish to crates. So, one software, one environment, and you can develop, publish everything all together. So, that's how uh it's simple. Everything is in Cargo. So, for uh starting the project, cargo new. If you are checking implementation and testing, cargo test. If you want to build and release, cargo build and release. So, >> [clears throat] >> this is very simple. And then, there are many other command that you come across in software development life cycle. You can have everything uh in this. So, that's how we have started this. And then, once you want to publish, just before publish, you can have a dry run, and you can publish. cargo.toml is your um you can say metadata, where you put everything about your software and everything. And this is used in indexing. Then, uh when you have to publish, you have done with your uh software, and you can just cargo login. You have to register on the site, and then you can do cargo login and cargo publish. And your softwares are published on the crate. So, it's very simple. And one thing just to remember that whatever you publish on crates, there is no recall. You cannot recall your software. So, whatever you publish, it is permanent with the version and everything. You can ank They use the term ank that can be just removed from the When people search, it will not show, but uh still it will be there. So, whatever you have to to you can just publish carefully. So, that's how uh I have built my uh CLI. So, any user who want to use my tool, they can just have cargo install and use the name and they can use. Or if I share that with GitHub or any other places, then they can use curl and they can use. So, now I would have a stopped here, but this having problem because I wrote a tool, I wrote a CLI that is very general in nature. Every developer can use and when I want to distribute it, the first solution ask user to install Rust and cargo ecosystem. Maybe my end user is Python developer or React developer or Next developer. Asking them to install Rust tool chain and everything is not a right way of doing it. Second part, maintaining second uh solution is also difficult and then user may not familiar with curl installation and everything. That also uh difficult and it can also uh raise security risk because install. sh what I am keeping, maybe end user don't know and they reluctant to use it. So, either of these solutions were not suitable for my use case. So, now I was looking for some other way like being a Python developer how I can use this tool with Python ecosystem also. So, from where I started uh trying this. So, distribution problem, that's what I was mentioning. So, Rust give us a single aesthetic dependency-free binary. So, when you write code in Rust, it you can get a single aesthetic uh binary. So, and using the multiple platform setup, you can compile your source code in multiple platforms. So, write once and according to the platform, you can have multiple version of same binary. So, that's that's like good and then every packaging system ecosystem have their own packaging format like in Python, you can use pip. Uh if you are from React, you can use npm. If you are using Mac Macintosh, you can use brew even on Linux also. And window also nowadays have repository base installation using winget. So, all these are different ecosystem to download tools and software. So, now creating a simple a CLI general-purpose, I want to explore all this. So, user, whatever platform, whatever ecosystem they are using, they can install our software. So, they have their own a schema and everything. So, I this talk is about how we can do it and what are the benefit of doing it. So, Python data, you have repository PyPI. For front-end node teams, they use npm. For Mac and Linux, they use Homebrew mostly. For Windows developer, you can directly download binary and install, but nowadays they have a repository base. Before 10 or Windows 10, they don't have. Always we download and then we install. So, this all have the repository. So, we don't want to have uh Rust in everywhere. So, we want to have follow this and then user can uh download our software. So, that is what title says, build once and ship everywhere. So, if you are building a binary or a software tool, you can build only one one source code and you can have multiple binary and you can ship everywhere. So, [snorts] then the the system will become like this. You are writing your code and then cargo build will create all the single native binary and then with uh GitHub or any automation CI/CD CI/CD, you can use to publish to all PyPI, npm, Homebrew, Scoop, Docker, or whatever uh releasing thing you want, you can uh follow that. So, in Rust, we have cross-compilation. So, what we can do when we are doing the build, we can pass targets, which OS or which system, which CPU we are targeting. According to that, our source code, they will create a single binary. So, for all the available target, we can have binary files. So, now it solves a problem that multiple platform, we don't have to make changes with one source code. We can have multiple binary, and all are individual binary, single by file. So, it will run in all the system. So, it will give something output like this. Uh unknown Linux, Arc, and all this like there are many other OS and platform, so you can get all the binary. So, this solve uh problem of having multiple target. Then, there are some target, especially targeting for low-end devices, where you have lots of issue with the security and installation of the package. That was not our target, because we are targeting developer. So, our OS are mostly high-end computational OS and devices. So, uh later I have removed that from build, and we target only the PC and all other target. So, now it's very simple CI. You build your your CI can build the target, define whatever you have targeted, and then attestation, you can verify. Currently, all uh it's actually a little bit threatening also that what I have observed, none of this uh package, PIP or NPM, they don't ask any signature or any certificate, except Bing get ask digital certificate or other uh scanning method. Otherwise, all this repository, they just allow you to update. So, that is supply chain problem. I think they all enforce certification and verification process, but that's very simple for other package manager. So, then you have your artifact, and then you just put all the artifact into multiple channel that you have decided, and then according to that you create your change change log. >> [clears throat] >> So, the same thing uh in a steps. So, now how we achieve this? So, we got binary for all the platform. Now, what we have to do according to the ecosystem or channel, we just have to apply wrapper. So, we wrap for PYPI the binaries, we wrap for NPM, and then all these package mana package repository, they accept our submission, and then user can download using their system. So, uh different package having wrapper like PIP use S distribution, NPM you have post install, Homebrew have some concept called formula where you can put into GitHub and directly you can download. Winget have uh manifest. They have three files that you have to create. Cargo already we have discussed, and a scope also work like that. So, now go through the PYP. So, we can package all the pre-compiled Rust binary according to the different uh target, and that will create different Python wheels, and then for this PYP I have used Maturion. It's very uh good where you can convert Rust to PIP packaging. It's very good package and software that you can use if you are working cross Python and Rust. That's very suitable. And then uh it's don't have any uh dependency on other problem because the binary is in one uh one file, and you can just have uh use Python modern CLI workflow also. So, this is Rust part, and then for having a Python uh PYP you have to create uh PY project TOML that is used by Maturion, and then they create the wheel for multiple target. Like this build, they will create target, various target, and various wheels they will create and then uh when the wheels are created, you can just push to the repository and your package is live on uh PyPI. So, in this what I was saying, they were not asking anything like even the MD5 or any any hashing or any just login with your account and you are good to upload. So, if my account get compromised, then anyone can upload any kind of binary. So, these are the risk uh in this platform, but that's how normally PyPI work. So, then once you have uh done, then you can your Python user can use pipx because pipx is now if you want to install any library globally in your system, then you have to use pipx. You cannot install with pip uh due to uh new changes in the system. So, now my tool was written using Rust. Now, a Python developer, if they also want to use .env file, they can also download, install, and then they can use the tool. So, now I can target Rust developer and also I can target Python developer, whoever uh I want to use the uh .env file. Similarly, moving forward, uh .env is also used mainly in all the React and JavaScript ecosystem. They have so many library that load .env file. So, basically, they have this this uh uh .env.local, .env.test, all this is there. So, that is also a big very big user group. So, now we want to distribute this via npm also because if you are a front-end developer, most of time you are installing JavaScript uh library and our tool is not a JavaScript, it is a Rust-based binary. So, then we uh follow this approach where we have to just wrap our software into their ecosystem and then it will work. So we have to package various according to various platform like for Linux, for Windows and all and then based upon this packaging whenever we publish this to NPM and then user want to install, they match with their platform underlying platform. It's Now it's become the NPM duty to match and find is a matching binary is there or not. Depending upon the matching, the it will be installed. So we don't have to do now anything. It's It's the repository. It's the distribution system that have to think whatever user is using, which platform they are using and then they will download and install. So my binary we just create once and the system will install it. So they The mostly it is sidecar kind of thing. This JS launcher they do all this permutation combination and which platform they have to download. Accordingly they just wrap and download resolve the binary and install. So now after Python, now if a JavaScript developer or TypeScript developer they want to install, they can just install using NPM or NPX if they want to install software. So now my software which was also useful for front end, they can also use my binary and they can also install from their their environment that what they know. They know NPM, they know NPX. They don't have to think about Rust, they don't have to think about binary and our tool is distributed to that community also. So now just I was keep going and then I tried to see how Homebrew work. So Homebrew have uh two-tier system. If your tools is very popular, then you can it will be part of Homebrew core. But, if you are new, then they don't accept direct submission. Then, they say you create a tap or you create a formula. That that is very simple. That is just a GitHub where you can have your uh formula and then user can So, this is just two-tier architecture, much safer than other two, and very simple also because it is just uh a small file that you have to create and a GitHub repository, and they will take care from there. So, this is how you create a formula in your GitHub repository. It is a Ruby file that you have to create. And then, you just give your source uh repository file name, and then the binary file and everything. And then, when user install, this will be run, and then the your binary will be uh resolve when installed. So, this is very simple. Uh we call it formula, Homebrew formula. So, it is >> [clears throat] >> simple in your CI also. It is very simple that you can just trigger and bump your version if you are releasing the new version. And the formula will just keep updating because when user install, they install from the formula. So, this is how uh Homebrew it is available on Mac as well as Linux also. So, they can just use either two a step brew and add your tap. You are with ENBX. This is the code. And then, they can just normally install how they install other software. Brew install EVNX. Or if they want, they can just merge both command and just install directly. So, now with this, ours binary is available for Linux as well as Mac Mac user also. And uh remember, I have just written one source code in Rust. And using this uh distribution system we can call we are distributing now to uh multiple uh platform. So, as I explained in the Homebrew, they have two tiers. One is core where the well-known software you will find, then you don't have to add the tab. And if it is new like my project, then you have to just use tab. So, the criteria like a star fork and all, based upon that later you can submit to the core. So, the the last one is uh winget. I think uh this one was, as I said, they have a very uh automated process. They use their because they have antivirus also, and they have put everything together as a scanning automated scanning. So, when you submit and uh my tool is reading file and all those, so they create a signature that match with some Trojan or malware. So, every time I submit a new version, they raise a uh Trojan warning, and then I have to go through their manual process and pass that process, then again resubmit our request, then only they accept. So, this manifest file we have to create, and then when we submit they create this Trojan uh warning. It is false alarm, but it is matching the signature, so they were raising uh the turnaround is I need to have a digital certificate, and then once I start signing my binary with those, then this will go away. But now it is a new project, and I don't have a digital certificate, then I was submitting all the version, and I have to go through the manual verification where I have to submit uh for this one, MMPHC, where I submit the binary. I I say the category and everything, and then after some time, hour sometime, 5 hour 6 hour, they clear it, and then again I have to resubmit submission to the their repository that PR then get clear and then my binary get released to their repository. So, this is little bit harder, but over time when the project grow, it will also solve. But, this is a good way that Window have moved from direct downloading EXE and installing 2 OS to a repository model and now they have a automated pipeline to verify also. So, this brings some security to the platform. So, this is the long-term solution that I see I need a certificate to sign. So, I I think I am out of time, so I will just a little bit rush. So, now similarly now it is a binary tool, so we can also have GitHub action because whenever you do a pre-commit or something, you can have as a part of your pre-commit code where this tool can run and do all the we have a scanning security scanning and all in the future in the tool, so you can use as a GitHub action also. So, I have created a separate GitHub action and published to the marketplace also, so it is available via GitHub marketplace and it can be consumed in any of the pre-commit like if you are using pre-commit hook, then you can also use this one. So, also nowadays everyone using AI for coding, so I have also tried to have a skill for ENV and then based upon that a skill your AI tool can use this tool because like if you have submitted your password or API keys or anything, you're having this a skill they can a scan your repository before making a push to the repository. So, those agenda skill also I'm trying to build and it is nothing but just a GitHub repository and then you have a skills. assets where if your assets are being used then it will show in rank, otherwise you can just download and install the agenda skill directly to your uh system. So, like NPX, it is by NPX a skill add. You can add the skill. Now your uh agent have these a skill and they can try to use this tool internally also. So, that is uh a skill. >> [clears throat] >> So, that was the how we have uh approached different channel. And then I also try with a scoop and also have a playground where you can test it. And normally, if you want, you can also distribute as a docker. And later I will look into the uh data. So, the aim of this talk was one binary, if it is general purpose or if you are targeting a large community developer community that come from different background, then how you can distribute your software via exploring this channel. And remember you are writing code only once and using the CI, you are publishing to all these platform. And this is only one time job. Once you have set up your CI/CD, you don't have to think about this channel and how they distribute because you just push and CI/CD, all these channels are automated. So, you can have uh your release automatically. Uh having a good uh software supply chain that will also help when you have set up this one. So, >> [clears throat] >> this all are the findings. So, once you binary artifacts finish, there there is a time taking because we are uh compiling for multiple version and then we have to retry, cache and everything. So, uh our signing key and token are also. So, all this we have to manage, but all this, as I said, it is one time. So, once you have set up and fix all thing, it will be like keep going. So, release time, it can be very fast. You are targeting lots of registry, and then your installation will go up. So, funnier story is the the Rust installation is about 300, where Python installation is in thousands, like 9,000 or something. In NPM, also, it is in thousand. So, if I have I would have a stopped at Rust, the distribution would have been very low. But, when I touch Python and NPM, the download of the binary tool have gone uh very high. So, that's all from mind. Thank you. Uh we can have some question if Yeah, lunch time I think is 12:10. We are 4-minute delay. Yeah. If you have any question [applause] Yeah. So, if you want to contribute, all project are open source. Yeah. Both project env-x.dev and .env.space, one is .NET specification, and one is about the project. So, if you want to contribute, you can also contribute either way. Yeah. Yeah, any question? I think all are hungry. Okay, then. Yeah. Okay, thank you. Have a nice lunch. Yeah.