Uh oh!
There was an error while loading. Please reload this page.
Install bcrypt backend for passlib - #7
Open
erkiaas wants to merge 1 commit into
Open
Conversation
passlib does not ship a bcrypt implementation, it only wraps one. Until now these images got away with it because passlib fell back to the stdlib crypt module, but PEP 594 removed crypt in Python 3.13, so any image rebuilt on current python:alpine (3.14) raises MissingBackendError: bcrypt: no backends available on the first hash it computes. For secret-claim-operator that is fatal: reconcile_claim() hashes on every claim, so the operator crash-loops and stops reconciling SecretClaims entirely. bcrypt is pinned below 5.0 on purpose. passlib 1.7.4's backend probe hashes a >72 byte test string to detect a historical wraparound bug, and bcrypt 5 turned over-long passwords into a hard ValueError, so passlib 1.7.4 + bcrypt 5 fails just as reliably as no backend at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
codemowers/secret-claim-operator:latest(pushed 2026-08-22 21:22 UTC,sha256:3ad6ab8c…) crash-loops on startup as soon as it reconciles its first claim:Because
reconcile_claim()hashes unconditionally (secret_claim_operator.py:53), the exception escapes the reconciler loop and the process exits — so no SecretClaim gets reconciled, not just ones using%(bcrypt)s. We hit this in a live cluster: the operator had been running for months and only broke when the pod happened to restart andimagePullPolicy: Alwayspulled the new build.Cause
passlibdoesn't implement bcrypt, it wraps a backend. With nobcryptpackage installed, passlib's only remaining option is the stdlibcryptmodule — and PEP 594 removedcryptin Python 3.13.FROM python:alpineis now 3.14, so the fallback that used to paper over the missing dependency is gone:Seven sample Dockerfiles install
passliband none install a backend, so they're all affected as soon as they're rebuilt;operatorlib.py:20builds aCryptContext(schemes=["bcrypt"])too.Why bcrypt is pinned
<5Adding plain
bcryptis not enough. passlib 1.7.4's backend probe hashes a >72-byte test string to detect an old wraparound bug, and bcrypt 5 turned over-long passwords into a hard error, so the probe itself raises:With
bcrypt<5(4.3.0) hashing works again on 3.14.Verification
Built
samples/secret-claim-operator/Dockerfilefrom this branch and ran the failing code path in the resulting image:Output format and cost are unchanged (
$2b$12$, 60 chars), so existing hashes stay valid.bcryptpublishesabi3musllinux wheels for x86_64 and aarch64, so the alpine build needs no Rust toolchain.Notes / possible follow-ups (not in this PR)
AttributeError: module 'bcrypt' has no attribute '__about__'traceback from its version probe.libpassis a maintained drop-in fork —libpass1.9.3 + bcrypt 5.0.0 works unmodified (import passlibandCryptContextboth fine, verified) and would let the<5pin be dropped. Happy to switch this PR over tolibpassinstead if you'd prefer that direction.secret_claim_operator.py:53(ctx["bcrypt"] = bcrypt.hash(...) # TODO: Use lazy getter) computes a bcrypt hash for every claim even when the mapping never references%(bcrypt)s, which is what made a missing backend fatal cluster-wide rather than only for claims that use it. Making that lazy would limit the blast radius of any future backend problem, but it is not a substitute for this fix.