I’m now really, really wondering why someone didn’t just make a test case. Sure, disable bcrypt for most of CI, but have like one case that actually uses it in the prod like way. Or say, integration testing. I really don’t want to rely on someone remembering and having to look in git history for this, I want the CI to fail if I do the the dumb thing.
Also bcrypt’s speed is configurable on purpose. It’s built to make it expensive for an attacker to try to brute force the password and also to hide timing information from them. You can make it faster in your CI where that isn’t a requirement and use the slower but more secure configuration in your production system.
Not the point of the article, but I’ve developed a tentative skepticism of runtime dependencies that are detected by seeing what is available in the environment as a pattern for modern SaaS.
I get that if you’re shipping something to run in a wide variety of end-user environments, things are complicated, and you probably have to probe your environment to find out what works, what dependencies to use, etc. But if you’re building an easily deployed container image for your application, you can just have the code that needs bcrypt say that it’s using bcrypt.
Your code should be factored in such a way that you can switch password hashes without changing hundreds of files (“dependency injection, or ‘passing arguments to functions, as we used to call it’”[0]), but once you do that, you’re not gaining anything by picking up bcrypt at runtime rather than at build-time.
After deeper investigation, I realized that bcrypt is actually a runtime dependency of our system.
And this is why we used to joke that dependency injection frameworks turn compile time errors into runtime errors. The advice in the article isn’t bad advice. But for the specific example it’s papering over the actual problem which is that no where in the codebase can you see bcrypt get used. It’s not pulled in by a package manager dependency it’s added by the applications list of dependencies.
Your intuition that there is something is wrong with runtime dependencies that are “detected” is problematic is spot on. In the name of making things easy many frameworks have made the trivial stuff easy and the hard stuff, like removing dead dependencies with confidence, impossible.
I’m now really, really wondering why someone didn’t just make a test case. Sure, disable bcrypt for most of CI, but have like one case that actually uses it in the prod like way. Or say, integration testing. I really don’t want to rely on someone remembering and having to look in git history for this, I want the CI to fail if I do the the dumb thing.
Also bcrypt’s speed is configurable on purpose. It’s built to make it expensive for an attacker to try to brute force the password and also to hide timing information from them. You can make it faster in your CI where that isn’t a requirement and use the slower but more secure configuration in your production system.
We actually did end up using it in CI and tweaking it to be much faster!
Not the point of the article, but I’ve developed a tentative skepticism of runtime dependencies that are detected by seeing what is available in the environment as a pattern for modern SaaS.
I get that if you’re shipping something to run in a wide variety of end-user environments, things are complicated, and you probably have to probe your environment to find out what works, what dependencies to use, etc. But if you’re building an easily deployed container image for your application, you can just have the code that needs bcrypt say that it’s using bcrypt.
Your code should be factored in such a way that you can switch password hashes without changing hundreds of files (“dependency injection, or ‘passing arguments to functions, as we used to call it’”[0]), but once you do that, you’re not gaining anything by picking up bcrypt at runtime rather than at build-time.
[0] Maybe quoting James Coglan? Not sure.
And this is why we used to joke that dependency injection frameworks turn compile time errors into runtime errors. The advice in the article isn’t bad advice. But for the specific example it’s papering over the actual problem which is that no where in the codebase can you see bcrypt get used. It’s not pulled in by a package manager dependency it’s added by the applications list of dependencies.
Your intuition that there is something is wrong with runtime dependencies that are “detected” is problematic is spot on. In the name of making things easy many frameworks have made the trivial stuff easy and the hard stuff, like removing dead dependencies with confidence, impossible.
Another example where it can help to do Problem:Solution: for your commits. Nobody cares what you did, they really care about why. https://lobste.rs/s/7fiajr/coping_strategies_for_serial_project#c_k9sd4r