We've spoken previously about security and software supply chains, and we're back at it on this episode.
We're diving in again with Charlie Coggins. Charlie works at a software supply chain company
and is on the episode to give us an insider's look and a defender's perspective on how to keep
our Python apps and infrastructure safe. This is Talk Python to Me, episode 457, recorded January 24th, 2024.
Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy.
Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython,
both on fosstodon.org. Keep up with the show and listen to over seven years of past
episodes at talkpython.fm. We've started streaming most of our episodes live on YouTube. Subscribe to
our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and
be part of that episode. This episode is brought to you by Sentry. Don't let those errors go unnoticed.
Use Sentry like we do here at Talk Python. Sign up at talkpython.fm/sentry. And it's brought to
you by Mailtrap, an email delivery platform that developers love. Use their email sandbox to inspect
debug emails and debug emails in staging, dev, and QA environments before sending them to recipients in
production. Try Mailtrap for free at talkpython.fm/Mailtrap. Hey, Charlie, welcome to Talk Python to Me.
Hi, Michael.
Great to have you here. We have corresponded back and forth about security things. And now,
you're scared. It's going to seem that way. There are threats everywhere, especially when you start
looking. And that's the problem. You look, you'll find them. And if you're not looking, you might get
affected without even knowing it.
Yeah, but that's true. But we're also going to come with some tools and techniques and tips on
how to avoid security problems with your Python code.
Yes, absolutely.
Yeah, I think it's especially concerning. That certainly catches my attention that if you mess
with somebody's software, like the software builders, the developers, it gets shipped to however many
users are on the other side of that equation, right? It's not like I just took over some
teenagers gaming PC, and now what can I do? It's like, I took over, you know, name your big web app,
and now we're going to start shipping some stuff around. All right, that's where the sort of
multiplicative aspect of this gets more concerning than just standard personal computer safety, right?
Oh, absolutely. You know, a single developer can have very broad impacts. You know, maybe they
publish one package, but that one package could be included in hundreds, thousands of other packages
as a dependency. And then everyone using those packages could be affected, whether the code is
good and works as intended or poorly written and has bugs and vulnerabilities.
Yeah, this is not to say there's any chance of there being a problem with Pydantic. But just to make
your point, if you go to like Pydantic or Request or something like that, a lot of these have used by
projects, right? And this Pydantic is used by 315,000 people, not people, software projects that
themselves have users, right? And so that's the kind of stuff that I'm thinking about when I said that
multiplicative effect, right? It's a big multiplier, not just a couple.
Oh, yeah. Yeah, for sure.
Yeah. Now, before we dive into our main topic, of course, you know, tell people a bit about yourself.
Hi, well, my name is Charles Coggins. I usually go by Charlie. And I'm a Python developer. I'm a
software developer, but not through the traditional sense. I don't have a computer science degree. I
didn't come to this, you know, straight out of school. I got my first taste of programming long
enough ago, back in the 80s, in 1987. My dad got a computer for us. And, you know, I was messing
around on there with some games, always with games, right? You know, at the time, it was basic.
You know, it was this bowling game that my brother and I would play. And I saw that I could look at the
code. I could look at the source. And I went in there and modified it a bit to make it so that I would
always win whenever I played him.
How long did it take him to catch on?
Oh, he figured out pretty quickly. And he was in there to change in, you know, ball speed and,
you know, how often he could get a gutter or get a gutter. But yeah, I, you know, took a class or two in high
school and college. But I was an electrical engineering major and then went to work for the government
doing something that wasn't even really that. So I spent 10 years working for the government before
they stood up the U.S. Cyber Command and decided or figured out that they needed to hire 6,000 new
developers to fill the positions. And there weren't that many available in the industry, let alone those
who could, you know, pass the clearances and work in that environment. So they looked to people already
working in the government. And I raised my hand. I said, yes, yes, I want to cross train. I'll be a
developer. And so they trained me.
Excellent. What did they teach you for language in that program?
We started with C, C++, and then there was some Python. So I went through a couple of boot camps and
a lot of self-learning, self-teaching. Python's the one that really clicked for me. It just made sense
in my head.
Yeah, of course. If you're learning to do cybersecurity stuff, you know, a lot of times I'd be happy to tell
people like, ah, you don't really need to learn C or Rust or Java. If you just know Python, you're
probably 90% of the time golden. But if you're trying to do cybersecurity, a lot of times it's about
like the machine level stuff, right? Understanding things like C and pointers and buffer overflows and
all of that kind of stuff is where you actually kind of need to be.
And they taught us all that as well. In fact, we learned assembly language as well. And that one
really didn't fit in my brain.
You're not like, I didn't want to become an assembly language programmer.
I mean, yeah, that's a whole different breed.
Yeah, it sure is. And, you know, it used to be, I remember when I first got into programming,
I was doing some C, C++ and inline assembly was something people would do a lot to optimize. A
lot like people might do Cython or Numba or something like that to make Python fast. Like we'll find this
little part and we'll rewrite it in this way and be like, we're just going to do inline assembly. I'm like,
that just doesn't seem like worthwhile. I don't need that much performance. We're going to not do that.
Yeah. Yeah.
Fun. So now you're working at Phylum. Is it Python focused or just software security?
It's not Python focused. In fact, the company primarily develops with Rust, as you were mentioning.
Okay. Yeah.
Yeah. Yeah. We've got some excellent Rust developers at our company. And I think that's what attracted
a lot of them is that that is the primary language we use. But we also have some elements in Python. And
when I came on board, I got assigned to work on our integrations. So like GitHub,
integrations, GitLab, pre-commit hooks, things like that. And so I was able to kind of architect it the
way I thought best. And because I love Python, I made it all in Python and exposed it through Docker
containers.
Are you doing direct integration with Rust, like Py03? Or is it more issuing commands out?
The Rust elements that our company works on, like our API, the command line interface, a lot of the
backend, it's just written straight Rust. And then the Python is just plain Python. There's no
interface between the two, really.
Yeah. Okay. Consuming APIs and Docker containers and stuff like that.
Right. Right. Right. Although I am interested in the Py03. And I think there's room to
bridge the two languages at our company.
I mean, for sure, people are adopting Rust for the performance foundations of Python. It's pretty
interesting.
Yeah. Yeah. I've been at the company almost two years now. I keep saying it's what I'm going to
learn next is Rust. And I felt like I would just kind of absorb it by going through code reviews and
the people on my team. It hasn't happened yet. I can kind of understand what's going on by reading it,
but I just, yeah, I need to jump in.
It's in depth. Okay. Got it. Those are the same. Okay. Got it.
Yeah. Yeah.
No, it's interesting. Okay. Well, we're not here to talk about Rust, although I do think
it's becoming one of those things that is sort of, I don't know if you need to be a little one level
deeper in the Python space that used to be C and now it's, I think it's pretty solidly moving to be
Rust, right? It's, there's a lot of popular things. Identic, for example, I pulled up earlier where
that's the foundation, but that also seems to be where the momentum is.
Yeah. The oxidation of Python libraries is a real thing. I mean, you know, look at Ruff, right?
Yeah. Ruff. I just heard about how Granian, I think it was, which is a new, similar,
similar to G Unicorn and Microwisky is a Rust-based async server. You know, there's, it goes on and on.
This portion of Talk Python is brought to you by OpenTelemetry support at Sentry.
In the previous two episodes, you heard how we use Sentry's error monitoring at Talk Python and how
distributed tracing connects errors, performance, and slowdowns, and more across services and tiers.
But you may be thinking, our company uses OpenTelemetry, so it doesn't make sense for us to switch to
Sentry. After all, OpenTelemetry is a standard and you've already adopted it, right? Well, did you know,
with just a couple of lines of code, you can connect OpenTelemetry's monitoring and reporting
to Sentry's backend. OpenTelemetry does not come with a backend to store your data, analytics on top
of that data, a UI, or error monitoring. And that's exactly what you get when you integrate Sentry with
your OpenTelemetry setup. Don't fly blind. Fix and monitor code faster with Sentry. Integrate your
OpenTelemetry systems with Sentry and see what you've been missing. Create your Sentry account at
talkpython.fm/sentry dash telemetry. And when you sign up, use the code TALKPYTHON,
all caps, no spaces. It's good for two free months of Sentry's business plan, which will give you
20 times as many monthly events as well as other features. My thanks to Sentry for supporting Talk
Python and me. All right, well, let's talk about software security though. You know, like we touched
on it a little bit with the multiplicative aspect of like why software developers should care.
But maybe let's start with some ways in which viruses might get on a computer from a software
perspective. Not from like, oh, you know, I found this cool app on BitTor and normally it's paid,
but this one's free. It's like, maybe don't install that. But, you know, not that kind of advice,
right? But, you know, specifically for software developers.
Right, right. So for software developers, I think the primary vector, you know, for malicious code
running in your environment or really any developer environment along the way, it doesn't just have to
be your system. It could be your CI, CD servers and your runners. It's going to be software
dependencies, third-party code, right? Code from strangers on the internet, right? That's really what it boils down to.
They just, Charlie, they're just here to help out. They're just giving you the code to help out.
They have no bad intentions. Right, right.
Except for that one. That one over there, don't take that one.
Yeah. And it's hard to tell, you know, what's good, what's bad. And I think we all rely on third-party code.
I mean, I think it's a rare company, rare project that writes everything from scratch on their own without any dependencies.
Yeah.
So that's a vector for sure, is allowing code from strangers on the internet to run. I think, like, the name of the game, right,
for attackers and threat actors is arbitrary code execution. Like, that's the key phrase.
Arbitrary code execution. If I can get arbitrary code execution with this vulnerability, then I've won.
I can attack your stuff.
You're going to get a CVE score of nine or above. It's right there.
Yeah, exactly. And that's for vulnerabilities. That's just, you know, poorly written code or code with bugs.
But forget about vulnerabilities. I mean, if you're an attacker, you're a threat actor, you've already got the perfect means to run arbitrary code,
to gain arbitrary code execution on a developer system. That's with third-party dependencies.
Open source software is just the perfect target for writing malware or slipping malware into packages.
Now, when people hear this, we've talked about it enough. It actually came as quite a surprise a few years ago.
People theoretically knew that it could happen, but that it was happening is that packages on package stores like PyPI and NPM and so on
got published vulnerabilities that people could then install and make part of theirs.
But there's a whole software supply chain, right?
Maybe talk us through some of the different elements that make that up.
Only one of which is these libraries, right?
That's right. That's right.
So the software supply chain is really it's using third-party code securely, as well as securing the end-to-end development process.
So that process is very broadly broken into three phases.
You've got the source phase.
That's source control management systems and then actually coding.
Developers coding on their systems, committing to repositories.
Yeah.
And you mentioned the dependencies like pip install this or that.
There's also, for many of the really popular IDs and editors, there's a whole massive array of varying levels of trusted plugins or extensions, right?
As well.
That's right.
Yeah.
Like Visual Studio Code, that's what I use for my IDE.
It's got an extensive extension ecosystem.
Just about anything you want to do.
I get a little pop-up when I open a new project and it says, oh, I recognize you're using a YAML file.
Do you want to download this extension that will lend to YAML files, right?
Yeah.
I got one for CBEs.
It was like rainbow CSV syntax highlighter or something.
I'm like, you know what?
That's not really made by a trusted company.
It's probably fine.
But I don't need my CSV files highlighted so much so that I'm willing to just run arbitrary code from a stranger on the internet.
That's right.
Right?
Yep.
And, you know, I use both PyCharm and VS Code and they both, especially PyCharm, has sort of a warning that says, this is untrusted.
It's a third-party thing.
Are you sure you want it?
Right.
Just saying no.
That's a pretty light warning.
Yeah.
And also, they're not the same, right?
Is it installed by a million people used every day?
Or is it for you the fourth person to use it?
And it hasn't, you know, hasn't had the experience of people going, why is it opening a network socket?
What's it doing?
You know, something like that.
Yeah.
That's another entry point you got to be careful about.
All right.
Well, I cut you off.
We're only in like square one of maybe nine.
Yeah.
Square one, source code.
And then there's the build phase.
That's where you take the code.
You take the commits that have gone into source control.
And you build something with it, right?
This usually happens in, you know, your CI, CD systems, GitHub, and Git Labs of the world.
And it's at that point where, you know, your third party dependencies get included and wrapped up into your artifacts, right?
Which brings us to the third stage of the software supply chain, which is the package and deploy phase.
That's where you're creating your artifacts and making them available to the world to use.
Could be anything.
Could be a wheel for a library that other parts of your company use to build software.
Yep.
Could be some app you ship.
It could actually be a website, an API.
Who knows, right?
Yeah.
Docker container.
Yeah.
Yeah, exactly.
And then by the time you get to that, you know, the end of the supply chain and, you know, the products or the packaged product that people are going to see and use and work with, you know,
you've baked in so many elements at that point, you know, from your third party dependencies to, you know, any other external resources that are getting called.
So there's lots of points along the way that it's possible to.
Yeah.
One of the things that can be sneaky is, you know, it doesn't happen that often in Python, but you're shipping like a Windows or a Mac app.
There's a digital signature proof of we're going to sign this with our trusted certificate.
So it doesn't even give you any warnings.
Like, look, this is it's signed by the company.
It is trusted.
Here you go.
Pick it.
Right.
And somewhere upstream from that, there's an issue like with packages or other things.
Well, that issue is now that that problem is signed and verified as well.
Yeah.
You know, so you mentioned you mentioned code code signing the research team at our company.
I mean, they're amazing, amazing group there.
They're always finding new and novel attacks.
And one they found just this past week involves something kind of cool where the attacker had bundled up a valid Microsoft binary.
It had been signed by Microsoft.
But they bundled it with a DLL that was malicious.
It was named something to be expected.
Right.
So when you run the executable on the binary, you know, you could see that there's this Microsoft signs application looking for permissions, looking to continue.
And you're like, oh, yeah, great.
Signed by Microsoft.
No problem.
But then it uses this technique called like DLL search order hijacking.
Okay.
That technique.
Right.
So if you have a DLL that's being called by the application more locally than not, that's what it's called.
So it's looking for something in like.
Yeah.
It'll look for the name of the DLL in the same directory first, basically, is what's happening.
Right.
They had shipped their bad DLL with a good binary.
So you pick something in system 32 that's got like a real common name like VC runtime whatever dot DLL or, you know, some of the standard ones.
But then you completely reprogram it.
Yeah.
And stick it in there with that app.
Or maybe not completely because you need the app to not crash.
But you give it some extra boost when it does something.
Right.
Yeah.
In this case, they had just copied all the files needed for execution into a new directory, including the known good binary, the known bad DLL.
And then, you know, it had everything it needed in that directory to run.
And it looked like it was legitimate.
Right.
Because a lot of the OS dependent, a lot of these OS checks are on the executable, the system libraries that they use.
Right?
Right.
You'll see like this, this executable is downloaded from the internet.
Are you sure you want to run it?
Like that doesn't say this executable, what you trust is maybe possibly using a library that you downloaded.
Like it doesn't say that.
Right.
Yeah.
Cause we could never get work done if there was that level of checking all over the place.
This is what updated somewhere.
This portion of talk Python to me is brought to you by Mailtrap.
We're going to keep this super short.
So please pay attention or you'll miss it.
Mailtrap is an email delivery platform that developers love.
An email sending solution with industry best analytics, SMTP, and email APIs and SDKs for major programming languages with 24 seven human support.
What makes them unique is their email sandbox.
Use email sandbox to inspect and debug emails in staging, dev, and QA environments before sending them to recipients in production.
Try Mailtrap for free at talkpython.fm/mailtrap.
That's kind of the space that we're talking about, right?
We've got editors.
We've got libraries that you use.
CI, CD pipelines.
Containers are super interesting as well.
And all the tools to go with those.
So let's talk through some of the posts that you've written and also just selected about some of these things.
And maybe starting to the front of that list there with block files.
Yeah.
Okay.
So, yes, I wrote a blog post.
I guess it's looking at the date on your screen.
It looks like it was over a year ago now.
And probably seems like yesterday, but no.
Yeah, that's right.
That's right.
So I'm sure the landscape has changed since then a bit.
And maybe there's some new players out there.
But, yeah.
Yeah.
I think one thing you can do as a developer, a big one I would recommend, is use lock files for your dependencies, right?
And, you know, what's a lock file?
Well, it's the fully resolved set of dependencies that are used by your application, your package.
And, you know, if nothing else, like, you should know what's going into your code, right?
Like, what?
Right.
Well, one of the ways this helps.
Yeah, exactly.
That's a really, that's a bit of a challenge, right?
And I think I'll admit when I first got into Python, I didn't do this that well.
And, you know, to me, it felt like probably the biggest issue I might run into is instability in my app, right?
Like, for example, if I don't pin a dependency, some new thing comes out, I reinstall it on a new computer.
Maybe it gets an upgraded version.
And there's some library that doesn't work, right?
I mean, there's been certainly popular libraries that just said we're having a major version change and we're fixing the mistakes we made 10 years ago.
And these three functions are changing or whatever, right?
That would break it.
But it could also be there's now a malicious version of library X and that's version two.
But if you pinned it on version one, even though it's bad, you're still not getting the bad one, at least for a while, right?
Absolutely.
Yes.
So I think I got to look it up.
I always forget.
Pep 665.
Okay.
Yeah.
Pep 665.
665.
It's a rejected PEP.
Unfortunately, but it was written by Brett Cannon, some others.
I know you've had Brett on the show a number of times.
I love the stuff he does.
Yeah, he does excellent work.
And it's kind of a shame this was rejected, but this Pep tried to create a standard block file format for Python.
And, you know, if you look into the Pep a little bit, you know, there's some motivation about like why you'd want to do this and, you know, four big reasons.
And the third one is when I really key on, which is that, you know, lock files allow for reproducibility.
And reproducibility is just more secure.
Because when, you know, I'm quoting here from the Pep says, when you control exactly what files are installed, you can make sure no malicious actor is attempting to slip nefarious code into your application.
IE, some supply chain attacks.
By using a lock file, which always leads to reproducible installs, we can avoid certain risks entirely.
And, I mean, that's the name of the game.
That's like, that's what our company focuses on, which is avoiding those risks by ensuring you know which dependencies you're using and you're knowing that those dependencies are benign or good, you know, doing no harm.
Even if there's something that happens, usually it's going to happen to a popular library because you're using it, hence probably other people are using it, other than type of squatting, which we can talk about.
But, you know, if you pin your dependencies, chances are it's, these things only stick around for a little while.
It's not like, oh, they discovered it had been there for eight months.
It's like, oh my gosh, we heard about it.
A few people got it and then we got rid of it, right?
Yes.
The folks at Pype are pretty excellent.
So it's, to some degree, a timing issue as well.
Yes.
Yeah.
Vulnerabilities are different, right?
Where that's what a lot of people focus on.
A lot of the tooling exists to, you know, discover vulnerabilities in your dependencies, which is good to know about those.
But those exist for a long time, right?
You have CVEs for known vulnerabilities and they end up in these databases and they're there for years.
And if you're using old dependencies or maybe transitive dependencies or using old ones and you're stuck on it, then you're going to be exposed to those vulnerabilities.
But what's different about that?
Examples of those include the WebP library not too long ago, right?
That was baked into Python and then also open SSL, right?
So people discovered issues in those.
Those are baked into different aspects of Python or some of the libraries.
And it's like, well, all of a sudden there's this fire drill.
Yes.
Which is different than somebody going, I'm going to sneak a thing into the library.
Right.
And then it is a timing matter.
So malicious dependencies, that's a whole other story.
Because if a malicious package is discovered, there's not a CVE created for it.
The package is just taken off of the registry.
You know, you report it to the good people at PyPI and, you know, they'll review the submission and take it down.
I've done a few of those myself and they're really fast.
But there's still a window of time where that malicious package, that malicious dependency is up and available.
And that's, you know, often all that's needed.
Yeah, exactly.
I do think having a pin dependency there is worthwhile.
Because if you make a commit, your CI runs, et cetera, et cetera, right?
Like the chances that you just bump the version to this malicious thing is pretty low.
Yeah, exactly.
So, yeah.
Yeah.
And having version ranges is not enough.
You know, you need to have explicit versions, you know.
Let's talk more about these lock files then, right?
So there's actually a bunch of choices these days.
You know, Brett's PEP tried to make it less of a choice.
Say, well, it doesn't matter if you use hatch or pip or poetry or whatever.
The outcome is the same.
And for reasons that I don't haven't learned enough about, I don't know why that didn't work.
But let's talk about what's out there now.
Because there's a couple options at this point.
Sure.
I think the, yeah.
So most Python developers are going to be most familiar with pip, right?
That's the standard.
And pip has requirements files.
And, you know, they're unique in the lock file world because they can be named anything, right?
Most other lock files have a defined name.
We were talking about Rust earlier.
You know, they're the gold standard for a lot of this stuff.
And, you know, they're very clear.
They have cargo.lock.
That's their lock file.
You can't name it anything else.
Its contents are well defined.
It is what it is.
But in Python with pip, I mean, you could name it whatever you want.
You know, dev requirements.ext.
You could name it cargo.lock.
But it can contain Python dependencies in it.
Surprise.
I'm not Rust.
Basically, you can just put more or less arbitrary commands that are sent to pip in a text file, right?
Yes.
Which is more or less what it is.
Yeah.
Yep.
Any command line option you can feed the pip, you can put in a requirements file.
It's cool because you can have an import by saying dash or some other file.
Yes.
But it's also not super structured.
You can get a hierarchy that way.
Mm-hmm.
Yeah.
So there are some tools available to turn those, like, loose requirements files, the pip requirements files, into strict lock files, right?
Where every entry is pinned to a specific version.
And pip itself can do it with the pip freeze command.
So that's the one most people know about.
But that one's kind of not so great because it only freezes the packages for the environment that you ran pip freeze in.
You know?
And maybe you're trying to publish your lock file for users of a different platform or system.
The other thing that I don't like about it is you want to put just the things you actually use into your requirements file.
Like, I'm using HTTPX and Pydantic.
That's it.
But what it really installs when you run that is the transitive closure of all those things.
Yes.
Which is fine.
But you're not necessarily expressing that with just your requirements.txt, right?
Right.
Yeah.
Your two packages could balloon to, you know, 100 dependencies.
And that's not uncommon.
It's not even that bad.
Like, in the JavaScript ecosystem, you know, the same handful of top-level dependencies could have two orders of magnitude explosion where you end up with thousands.
There's a really...
Oh, gosh.
I can't find out.
You know what?
I think it's on...
I think I put it on the Python bytes.
But there's a really funny...
I want to be able to pull this up for people so they can find it.
There's a funny, funny thing that somebody did.
Well, for some definition of funny.
They put...
Somebody created an NPM package called Everything.
Yes.
And there's an article called Everything Becomes Too Much, the NPM Package Chaos of 2024.
Yeah.
An NPM user named Patrick JS launched a troll campaign with a package called Everything, which depends on every package in NPM.
Yeah.
And that's...
I think it's the...
NPMs are the largest package registry out there.
So it's...
I mean, it's already massive.
I remember your early episodes, you would recount how many packages were on PyPI.
And then we got to that...
I don't even know.
Are we past half a million?
...6-figure number?
Well, yeah.
I remember it was a big deal.
It got up to 100,000.
And now it's probably, what?
400,000?
500,000?
Over 500,000.
509 by rounding.
Yeah.
Half a million.
Congratulations, world.
Amazing.
Yeah.
I just added two new ones last week.
So I guess I've made a huge difference in that number.
Nice.
Yeah.
So basically, the pip is awesome and it does a bunch of great stuff.
And one of the things I really like about working with pip is I don't need to teach people anything if they want to work with my project.
Right.
I don't need to teach them like, oh, I know you love poetry, but I'm using a combination of the hatch build back end with PDM.
You're like, what?
I don't even know what those are.
Right?
Like, there's a lot of, like, ways in which you work that are brought in with a lot of these tools here.
So pip is kind of like, you know, it just kind of works, right?
Yes.
But having this transitive closure managed is not part of what it does, but it's super important because if I need to upgrade something, I can't just change my version number in my requirements.
Because that doesn't affect its dependency possibly, right?
Like, it depends what it's said.
So I'm a huge fan of pip-tools.
This is actually what I do most of the time.
Yes.
pip-tools is another one.
You can, it's great.
I think it has this pip compile command that will take as an input, I think, just about any Python manifest type that's out there.
So you can do setup.py, requirements.txt.
I'm forgetting the other ones.
The pip.ev.lock, maybe.
Setup.cfg, pyproject.toml.
It just recognizes all the different ways people could express their loose requirements, you know, the manifest files.
Yeah.
So, yeah.
Yeah.
I really like it.
And you can say pip compile upgrade and it'll look at all the dependencies and upgrade them all as high as they can go.
But what's nice about that is you'll be working for a while.
Then you choose, like, well, let me just do a refresh on the dependencies right now and repin them and see how that works.
And then just carry on with your business for a while, right?
And it'll manage that transitive closure as well with, like, actually a really nice lock file where it described, like, these are all the things in the lock file.
And the reason that, you know, for example, in your blog post, you say they're certified of this version.
And it's there because you asked for it and because request needs it.
You know, if you're like, why is this in my virtual environment?
Why do I have this weird thing that I don't know?
Like, it'll tell you, here's why it's there.
Yeah.
One of the downsides, though, I think pip-tools has this issue.
I know pip does, is that in determining that transitive dependency resolution, it is very possible.
In fact, it usually happens that you have arbitrary code execution on your system, right?
Like, if you start with the two top-level dependencies, like you mentioned, and it lists dependencies, well, then it'll pull those in and it acquires the metadata.
From the wheel, if that exists.
But if it doesn't, it'll build the package just to get the metadata filed, just to figure out which dependencies that needs.
Are you saying I should set up a Docker container to execute this?
I mean, that's, yeah, that's kind of what's happening.
Maybe I should, yeah.
Maybe I should.
And, you know, yeah, running in a sandbox is another option, right?
Where that's what my company, Phylum, that's one of the solutions we offer.
You know, we have extensions for our CLI where you can wrap pip by just calling Phylum pip.
And then everything runs in a sandbox.
So that's another solution.
Yeah.
So good.
Because, I mean, pip is a funny one because they even have a command line option called dry run, tac-tac-dry run, which you would think, oh, nothing's going to happen on my system.
It's just separate.
Running code from strangers on the internet.
But it does.
Yes.
Dry run, even using dry run for pip install and pip download commands will or has the possibility of downloading and running arbitrary code from strangers on the internet.
If we had, oh, wheels came along far after pip, right?
And we've got the source distributions and setup.py and all that kind of stuff.
And so if wheels existed from day one, it very well would be the case that this is not a problem, right?
But, you know, what is pip supposed to do?
Like, it has to evaluate this dynamic thing to figure out what it wants.
Yes.
Yeah.
Wheels are great because, you know, they have a metadata file in there that clearly lays out what the dependencies are.
And there's no arbitrary code running when you install a wheel.
It's just extracting and copying, you know?
Yeah.
A wheel is just a zip file.
You extract that zip file and then copy the contents to various locations.
But, yes, as you said, because we've had source distributions, tarballs, and then even eggs before that,
and I'm probably never going to fully get rid of those.
It just takes one.
One dependency anywhere in your chain that is only distributed as a source distribution.
Before now, you're downloading and building a package just to get metadata to continue.
Yeah.
And maybe you didn't actually choose it, right?
It's the dependency of a dependency of a dependency.
Absolutely.
Yeah.
That's, yeah.
Yeah.
You know, people often respond to some of the findings our company has where we'll, you know,
we'll post these malicious packages with all sorts of crazy names.
And people will respond to say, like, you know, why would I install that?
Like, why would I ever install this, you know, random package that no one's heard of?
It's like, well, you wouldn't.
It's, it's, it's, it could be, but it could be included in, you know, the transit dependencies, right?
If it gets, if it gets added to a slightly more legitimate package or, you know, worked up the chain that way, then, then yes, eventually, you know, you'll be running it unknowingly.
Yeah.
I think there's two important things we should talk about this before we move on, because there are some interesting ways in which you might unknow it.
You might even try to do the right thing and you might actually shoot yourself in the foot by doing so.
So number one, these like super strict lock files are awesome when you're building an application.
I want to ship Talk Python training out.
It's got its strict APIs.
It runs on this version.
It uses that version of Pydantic, that version of Beanie and whatever.
Yeah.
I want that to be fixed, fixed, zero flexibility until I decide through maybe a pip compile upgrade or whatever.
I want a new one.
However, if I was building a library that someone else was using, I would do them many headaches and a disservice to say, I, I depend on Pydantic 2.7.0.
You're like, well, my other library needs Pydantic 8, 2.8.
Right.
And I can't use it and your library together.
Right.
So you need the, it's, it's a different story when you're building a library that others are going to consume than it is when you're building an application.
And there was some, some disagreement, I guess, about the recommendation of pipenv for a while.
And it's because I believe that pipenv is really focused on the application side.
And it, I don't think it was made super clear that maybe it doesn't make as much sense for libraries.
Right.
So you want to speak to that a little?
Yeah.
I'm, I'm an advocate for lock files for everyone.
Right.
Applications for sure, but also libraries and their developers.
Right.
Cause you know, if when you, when you, when you distribute a library, sure.
You know, loose dependencies is, is probably the way to go there.
But library developers, people who want to contribute to your projects, the developers themselves, maybe you work on a team.
Having, having a lock file alongside your library is still going to be useful.
Right.
Like.
Yeah.
Cause that way you can say everyone, if somebody makes a change or they report a bug or whatever.
Yeah.
They're not bringing in a change from a different version of a dependency or like maybe something changed.
Right.
Yes.
Yeah.
Um, and then, and it, plus it still allows you to, start from a known good spot.
And then, maybe, maybe if you, if you know, you want to get the latest, then you can do it in a controlled environment, you know, like a sandbox or maybe a, on CI, you know, in a, in a throwaway runner that has no access to any, any secrets.
Or, sensitive.
Uh, sensitive.
That's interesting.
I hadn't really thought about having a specific requirements lock file type of thing for the libraries that I've been working on for the developers, right?
For people who want to contribute.
Um, because it's just been like a loose requirement so that people that built against it aren't pinned into some very specific thing.
But yeah, that makes a lot of sense.
I think.
Yeah.
There's a, there's a link in that blog post.
It's kind of dated now, but it's from the folks who built yarn, you know, JavaScript ecosystem.
But, they had, they say it a lot more eloquently than I can.
Uh, yeah, that's the one, lock files should be committed on all projects.
Yeah.
It's, I mean, it's a bit old now, but, but they, they go down the lists and spell it out a lot more clearly than me.
And that's why, libraries even can benefit from, from publishing a lock file.
Yeah.
People can check that out.
That's cool.
Yeah.
And Java, that's the JavaScript package manager.
So in JavaScript years, like a hundred years or something that's been a couple of years.
That's right.
Yeah.
You got dog years.
You got JavaScript years.
JavaScript years just tick by like second, the second hand.
Yeah.
All right.
Uh, cool.
So I see we're making great progress through our list of things to talk about here.
Um, I've gone through three and I like 15 left.
We'll have plenty of time.
Uh, so yeah, let's see.
So another one, another pep, I think we're talking about here is 517, a build system independent
format for source trees.
I have no idea what this is.
What is this?
Yeah.
Pep 517 and 518 kind of go together.
This is, this was like the transition away from setup.py towards pyproject.toml.
Uh, 518 is the one that specifies pyproject.toml.
Um, kind of things that go in it.
And then five, 517 is all about, build systems and build backends.
Uh, so, so like in your pyproject.toml and your, in your, in your, build system
key, you know, you'll often see things like, poetry core or flit or hatchling or,
these kinds of things.
And, and so it's five, PEP 517 is, is specifying what it means to be one of those build backends.
Um, it's really just defining two mandatory hooks.
What does it mean to build wheel and build sdst?
Uh, there's three optional hooks as well.
And I think there's even another PEP that followed on from this that talks about, building
editable, packages or, or, right.
The dash, the dash E equivalents.
Yeah.
Yeah, exactly.
Um, but really it just boils down to, defining a way to build a wheel and build
a source distribution.
Yeah.
And this is part of what opened up all the different choices we now have for package management and
things like that.
Right.
Cause now there's a common way they can all work together a little bit like WSGI.
Yes.
Yeah.
I've been using hatchling for my build back in recently and it's been working real nicely.
Okay.
Yeah.
I, I was just looking at hatchling the other day and they've got, yeah, yeah.
They, they're one of the, they're one of the build backends that offers, build hooks,
which, you know, so prior to, pipe project.toml and, and, and, and, wheels
and beat us wheels and you go back to the source distributions and your setup.py files where
it's just Python code.
You can be, you can be doing anything in your setup.py file, which runs when you
install the package.
Um, well now we're starting to see, you know, methods to do the same thing in these, in these
more modern packaging or build backends.
So like hatch has their, build hooks, build system hooks where you can, you can, you
can, you can, point it to think, yeah, just Python code and have it, have it run as
part of the build.
Yeah.
At least it only runs at build time, not install time.
Uh, right.
Yeah.
I'm looking at the documentation now.
I, I, I, yeah, this is still new to me, but there might be hooks for, for install as well.
Okay.
While you're thinking about it, one of the things I got a couple of questions I want to highlight
from the audience here, but also one of the, one of the things that I think maybe was considered,
I have no awareness of this, but if it wasn't would be excellent is what if the people at
pip just pre-computed all that metadata from, at least for the common platforms that you would
get that pip needs to download, run, set up pie, and then throw it away just to get that
data.
Like for Mac, Windows, and Linux, you know, if it would just go, okay, we're just going
to like, as you upload it, it would just kick off a job that does that on those three platforms
and put it in a JSON blob.
Yeah.
It seems like that would be worthwhile.
I, I, I'm fairly certain there's discussions already around that type of a solution and
maybe even a PEP for proposal, for it, but, yeah, getting away from having to build
a package just to get metadata.
Uh, yeah.
You got packages that are downloaded billions of times with a B it's insane.
And if somebody could do that three times instead of a billion times, it would make
it work faster and it would also make it safe.
Right.
I think it'd be great.
Yeah.
All right.
A couple of questions here.
Uh, this one.
So Tony on the audience says pip compile is great for finding your transitive dependencies.
One interesting thing that they've done is package up code with pants build, which supports
locks files just to look through what code gets packaged up.
Is this anything you've explored?
Uh, I've heard of pants.
I haven't looked into it myself yet.
Mm-hmm.
Um, okay.
Yeah.
So just use it like, go, okay, you're going to have to build this thing and give me a little
manifest and whatnot.
And then we can just look at that.
That's cool.
Yeah.
And then Tamir says, do you have a solution for taking already locked dependencies with you
when you start a new app?
I'm guessing, you know, maybe, yeah, I don't know.
I, I guess maybe you've already got a project you're working on.
You want to say like, I want this project to use that.
Probably you could just copy the, the lock file.
Right.
Yeah.
If you, I mean, if you really, I mean, really you're going to, if you start a new project,
um, or new application, you're going to, you're going to have new, manifest file, you know,
pyproject.toml, maybe you have the same dependencies, the top level dependencies or not,
but the, the fully resolved set of dependencies that makes up your lock file, that, that, that,
that can very easily be different.
So I'm, I'm not exactly sure how you just poured over one to another.
One more bit from Tony.
This is, something that I now remember from pants is this, if it just looks through
your code and if you use the import statement, regardless of whether you've put it in your
requirements files, it'll figure out what your requirements file should have been.
If you were a bad developer, basically.
That's kind of cool.
Just to see what it uses.
Yeah.
Nice.
All right.
Uh, onto the next thing.
Specifying PEP 518, specifying minimum build system requirements for Python projects.
Yeah.
I'm guessing related.
This is pyproject.toml.
This is the, this is the, the PEP for that.
Okay.
There's not much to it other than to say that they've settled on that name, rejecting a bunch
of other possibilities.
And then they've got the, you know, the, the few entries that are required, like for your,
your finding your build system.
Excellent.
Yeah.
You don't have to have a pyproject.toml for Python, but.
No.
Yeah.
If you're building a Python library and you don't want to use setup.py, then you're much
better off having a pyproject.toml, right?
Yes.
Yeah.
It's more in the library side that it, I mean, it's not that you can't use it on an application,
but it's more required on the library side.
Yeah.
That's the thing.
All right.
So let's talk about some of the ways in which your packages might go wrong.
We've already talked about typosquatting and we also talked about everything that's different.
Yeah.
But yeah, typosquatting is, it is tricky.
I think it's pretty well understood at this, this point, but maybe just tell people real
quick to cover that base, you know?
Sure.
Typosquatting is, is, you know, publishing a package with a name that's similar, but not
the same as, as a, as a existing known good package.
Right.
So like, instead of requests, maybe you, you get request without the S or, you know, one
that gets me cause I, cause I make the typo all the time was, is the cryptography package.
Like, like if I, you know, if I put you on the spot, would you know how to spell cryptography?
I always get the first couple of letters, you know, jumbled up a bit and, and there have
been malicious packages published and then taken down with, with the, you know, spelled C-R-P-Y
instead of C-R-Y-P cryptography.
Right.
Yeah.
But, but the idea is that, you know you, you, you can overlook a package cause it looks like
a, it looks like a good one.
No, it's not necessarily that you're going to, you're going to install it because you type
it wrong.
Um, although that is, that is, you know, one technique, right?
The drive-by installs where someone just bat fingers, the package name.
Um, but really having a, typo squatted package is going to allow these threat actors to,
be a little more stealthy in their inclusion of that package in, in legitimate, code
reviews and commits and, dependencies of dependencies.
Right.
And so the other, the other thing that goes with typo squatting, I don't know if I had a link
for you there yet, is, is star jacking.
So, a lot of times if you're going to typo squat on a known good package, okay, there,
there it is.
Um, you know, these, these, these threat actors, they just, they just straight up copy the
known good project, right?
It just cloned the repository and then changed the package name.
Um, and, and then when they, when they post the package to, PyPI, for instance,
the metadata that goes with the package, still exists, right?
So, on PyPI for a given package, you can see on the left-hand side, it shows like some,
some statistics.
If, if the, URL was given to like a GitHub.
hosted project, for instance, it'll go in there and tell you how many stars.
Right, right, right.
You know, how many downloads.
That's actually a signal that it seems like it should be good, right?
It'll have.
Yeah.
A lot.
And that's what star jacking is doing is just copying the metadata of a known good package.
Uh, so that on first look.
Yeah, there you go.
You can see.
Like I did pull up pytest and it says statistics, GitHub statistics, 11,000 stars, 2,000 forks.
Okay, this is legit.
Let's install it.
Right.
So I could go clone pytest repository right now, change the name to pytest spelled P-I-T-E-S-T.
Mm-hmm.
And then, and then push that to P-I.
The math version of testing, yeah.
And you're going to get these same statistics and you're going to get the same, maintainers
that you see if you scroll down a little bit, in the, the, metadata.
Yeah.
So you get the maintainers list.
All of that metadata that you, you, you enter in your pyproject.toml or setup.py file,
gets read here on PyPI and just, just publish.
So you can, you can fake people out.
Yeah.
That's actually really, okay.
Well, there's a new terrifying thing that I hadn't thought about.
Yeah.
So, so star jacking and typosquatting where you just take a known good package, clone it,
and then maybe you, you make a change to, you know, existing function, you know, the
function does what it's supposed to do, but it also does some other stuff like ship off
secrets from your, your CI server or, you know, it could lay dormant and wait for,
uh, some sort of production environment and grab some SSH queues or something terrible.
Yeah.
That's, that's, that's the other, the other dependency confusion.
Okay.
That's the next one you've got up.
Yeah.
This is the one that we kind of talk, it's similar to what we talked about, before
with, I can't remember, but I said there's, there's going to come back to this.
So here, here it is again, this is a dependency confusion where, if you get the wrong version
or the wrong name, it could actually, you try to be safe by having a white listed list or
say, well, it's, it's, so this is one where it's the same, same package name, different source
of where you acquire that package.
Yes.
So this is, you'll, these attacks are mostly like, companies, enterprises.
This is the enterprise attack.
Yeah.
So it's an artifactory and we, we only put our stuff there and we're, we're going to call
it like, you know, international company underscore data access.
That's right.
And, and it's, and it's, and it's tricky because if you don't know, like if you don't
have your build system set up in a way and then, your CI server set up in a way to
install your dependencies in the proper order, like excluding public registries first and only
looking for packages in your private registry, then it's very easy, especially with pip, which
defaults to looking on pipe PI, the public registry first, and then only falling back to your, your
extra index URL specifications.
Secondly, that if you, if someone had the knowledge or just guessed at the package
name that you had published on your internal registry, and then they made their own package
with the same name, but put it on pipe PI, that's the one that's going to get installed.
Um, and there was like a whole series of, you know, bug bounties that were claimed over this
back a few years ago, because people just went around, you know, guessing at internal package
names or maybe they used to work there or new people.
Yeah.
I'll pay a hundred bucks just to share your quorum at Sot.txt with me.
Right.
You know, it's, it's kind of, it's extra sneaky because it only affects people.
It only affects people who are going out of their way to be more secure, right?
They're going out of their way to say, we're only going to, we're going to actually set up
a whole server and we're going to whitelist a bunch of stuff.
You can only ask for the names of the things on this server.
And, ah, yes.
Yes.
And that, that might still work if you limit it to your internal registry only or a mirror
perhaps of, of the, the public registries.
Um, but it's pretty easy to create your own internal copy, download a bunch of external
ones and mirror them locally and say like, these are the ones that are pre-approved at
our company.
Nothing else.
Yeah.
I, I, I've worked in a environment where that's exactly what we did.
And, I think there is merit to that.
You just have to know that anything you're mirroring to the trusted internal network is in
fact secure.
You know?
Yeah.
For sure.
I think it doesn't really make sense except for a few very rare cases to say you cannot
use external dependencies.
Right.
You're just saying what we want is to not build software, but while the rest of the world
does, you know?
Yeah.
Because that's part of the magic.
We just saw there's over half a million libraries you can choose from.
When you say we, we have zero of those, you're really, really constraining the type of software
and the velocity at which you can build.
Yeah.
It reminds me of, there's that line, you know, like why, why do you rob banks?
Cause they have the money.
Cause that's where the money is.
Right.
It's like, well, why do attackers, why are attackers going after open source software now?
Like, well, that's, that's where it's easiest to get arbitrary code to run.
That's where developers are.
That's what, to be fair though.
It's not only, it's not only right.
There's solar winds, which really had almost nothing to do with open source, but it had
to do with CI, CD systems and other sneakiness.
Right.
Yeah.
And got into places that, you know, instead of getting into libraries, you get into the
build system and you just give it a little extra, a little extra include tag there.
Bringing that deal out, like you said, right.
So dependency and confusion is sneaky because you're asking for a local version off a local
server.
It doesn't exist on PyPI, but if it could be made to exist on PyPI, all of a sudden that
gets installed.
That's potentially, that's not good.
Potentially.
Yeah.
It's, it's, that's, that's how it works in all the, in all the default cases.
And it's, it's pretty tricky actually to, to exclude, to do it in the correct order and
exclude those public registries.
Yeah.
What's what I do to help this is I just, I just run the UUID command to get one of those
16 digit arbitrary X things.
And I just name all my libraries that.
And so it's like, oh, you have the F3DC.
Yeah.
That's the, that's the API one.
That's right.
That's important.
That, right.
No one is going to do this.
It's such a safe space.
I tell you.
All right.
On to the next one.
That, that would work.
Expired author domains.
This is super sneaky.
Yeah.
So this is one, you know, it, it might be less of a factor now.
I think, I think it was just earlier this month that PyPI enforced two factor authentication
for all their users.
But a lot of sites and, you know, even PyPI, I think before this month have, you know,
password reset features where if, if you lose access to your account or you forget your password,
just, you know, send me an email and reset your password.
But it's, it's, it's very possible that people, you know, years ago submitted a package.
They, they don't maintain it anymore.
They submitted it under an old email account that has expired.
Right.
Maybe they, they had some domain.
Yeah.
Special.
It doesn't work that well for Gmail or Outlook.
Right.
If you had.
Custom domain.
If you had a custom domain and, as would be awesome, have your own, you know, Michael at
talkpython.fm, that kind of thing.
Yeah.
Say you, you win the lottery and, and, you know, decide to quit your pay job.
Yeah.
And then you let your domain expire and, well, maybe there's still a linkage for the talkpython
domain to PyPI.
And then I go and buy that domain and, you know, request a password.
Set up the server.
Yeah.
Account reset.
Set up email.
Yeah.
And then now I, now I can publish new versions of, of the, of the packages there.
Yeah.
It's not good.
Yeah.
So I don't really know what to do about that one, but there's an amazing, there's an amazing
joke that I found on Mastodon.
Somebody posted, sit here.
It's two big red buttons.
Think Ren and Stimpy or whatever.
And one of the red buttons says, admit to yourself that your dream is dead.
The other one says pay $12 for domain renewal.
Right.
I mean, it's funny, but there's plenty of people who will get a domain and I totally go in and
then it's like, you know what?
I haven't done anything without five years.
I'm not paying another 12 bucks.
But if they had set up an account under that, right?
This is what you're talking about.
Yeah.
Yeah, exactly.
Yeah.
That's why you got to buy your domains for that hundred year renewal period.
Exactly.
Take out that loan.
You get to the loan.
All right.
We're getting short on time here.
I want to, let me, let's just go through, I'll just list off a few real quick.
Maybe we do lightning round.
Okay.
Unverifiable dependency.
Okay.
These are for specifying dependencies that are not necessarily published to PyPI, right?
So that maybe you're pointing to a GitHub repository.
You know, pip calls these VCS project URLs, you know, if you look in their help output.
Yeah.
It's like pip install git plus HTTP to a thing that has a PyProject autonomous.
Yeah.
And that thing, it can point to a repository.
Maybe it points to a tag.
Maybe it points to a branch.
None of that is stable, right?
Like you, the tag could change out from under you.
The code that's related to that tag could change out from under you.
The code at the branch you're pointing to could change while the name remains the same.
So, you know, those are risky for that reason, right?
If you're not pinning to a very specific version or a very specific hash, right?
If you're going to point to a repository or a git URL.
Interesting.
Yeah.
Make sure it's true.
I've gotten to feel a lot of times like the hash is maybe a little bit redundant given the immutability of PyPI.
But if you're pointing at something like this, then maybe all of a sudden you really do want that, right?
Yes.
For sure.
Yeah.
Okay.
Repo jacking?
Yeah.
This is similar to the expired author domain, right?
So if someone was pointing to one of those git dependencies, a VCS project URL, as pip calls it, and that account went dormant or expired, relinquished, whatever, and someone else took it over, then yeah, they can now dictate.
What's there, yeah.
Yeah, exactly.
A lot of people are acquiring.
All right.
And then maybe last bit, get a chance to talk a bit about your Phylum CI project.
I do want to point out really quick, though, that Phylum was a sponsor of the show.
Yes.
A while ago.
But this is not a sponsored episode.
This is just you and I had been talking prior to that, actually, and decided to put this show together.
So just to be clear, but let's talk about this project you guys got anyway.
Yeah.
So you can pip install Phylum right now, or like I prefer, pipx install Phylum.
Yeah.
I love pipx.
It's awesome.
Yeah, me too.
Yeah.
I think I heard about it from you, actually.
So the circle goes.
Yes, yes.
So this package, it does two main things.
One is it can, it'll expose us to entry points.
One of them is called Phylum init, and that'll get you the Phylum command line interface written in Rust, but installed with Python.
It'll get you the Phylum CLI locally.
And then the other one is called Phylum CI.
That's just a catch-all entry point, the thing that gets exposed through our Docker container.
to handle almost all of our integrations.
So if you want to monitor your PRs on GitHub, for instance, we've got an integration for that.
Nice.
So the idea is basically that I could set this up in GitHub.
A PR comes in, I could set up an action.
Phylum will scan it for known mischievousness.
That's right.
And make that part of the PR, maybe even block it out, right?
Yeah, exactly.
It'll fail your build if you don't pass your default policy or established policy on any of your given lock files or manifests.
We deal with manifests as well.
And you mentioned GitHub.
So even with GitHub, we went a step further.
We have an app as well.
So you don't even have to modify a workflow.
You could just install a GitHub app and automatically monitor your repositories.
But a lot of the other ecosystems don't have that.
So we just provide Docker containers.
I love the Docker container.
So use Docker run against your code or whatever.
So yeah.
And then there's even a pre-commit hook we expose as well.
Nice.
I genuinely don't know the answer to this question.
Does this cost money?
No.
We have anyone.
Anyone can sign up for free.
There's a community edition where you can have up to five projects.
Okay, cool.
You guys have to eat.
There must be some way you charge for something.
Oh, exactly.
Yeah, yeah.
So there's the paid version, right?
Which, you know, unlimited projects.
You get access to group-based management.
You know, there's a few extra features.
It's a freemium model.
More of a Teams enterprise-y angle.
Yeah, yeah.
But for this audience, I mean, I would love if everyone just went that little extra step of securing their open source software and, you know, go with the free option.
I'm not trying to sell you anything here.
You know, monitor your manifest, your lock files.
Make sure that you remain secure.
You're not exposing your secrets because that's what we're finding now is that developers are the new high-value targets.
Yeah.
That's what attackers want to go after because we know that developers, they have the secrets.
They've got the keys, you know.
We write the code that then gets run on the production server inside the firewalls.
Yeah.
We have all the access, all the secrets, all the keys.
So, you know, if you can find a way to get arbitrary code from strangers to run on developer systems, you're going to have a much better chance.
We have a good time.
Yeah.
We have a good time.
By that, I mean having a bad time.
Right.
Yeah.
Doing bad things.
Okay.
Let's not do that.
Awesome.
Well, excellent work.
I think probably we'll kind of just leave it there.
We're pretty much out of time for the rest of the stuff.
But close it out for us, Charlie.
People are maybe both have a few new tools to work with, but also techniques, but maybe also a little freaked out.
What do you tell them?
I recommend everyone to restrict their use of dependencies to lock files and then carefully gate or guard the inclusion of new lock files or updates of existing ones.
Or sorry, dependencies in those lock files with careful analysis.
Don't allow arbitrary code to run anywhere in your development process and give FileM a try.
We've got the free community edition.
We will provide that analysis and ensure that you don't have malware running on your system through bad dependencies.
Awesome.
All right.
Well, it's been very interesting and a lot of new things to think about.
So thanks for being here.
Thank you, Michael.
Yep.
See you later.
This has been another episode of Talk Python to Me.
Thank you to our sponsors.
Be sure to check out what they're offering.
It really helps support the show.
Take some stress out of your life.
Get notified immediately about errors and performance issues in your web or mobile applications with Sentry.
Just visit talkpython.fm/sentry and get started for free.
And be sure to use the promo code talkpython, all one word.
Mailtrap, an email delivery platform that developers love.
Use their email sandbox to inspect and debug emails in staging, dev, and QA environments before sending them to recipients in production.
Try Mailtrap for free at talkpython.fm/Mailtrap.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show.
Open your favorite podcast app and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.