2 पॉइंट द्वारा GN⁺ 2024-03-27 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Rust ecosystem में जैसे ही कोई abandoned dependency RUSTSEC में चढ़ती है, वैसे ही सीधे तौर पर प्रभावित न होने वाली लाइब्रेरी भी users और CI के ज़रिए तकनीकी कर्ज़ बन जाती है
  • insta जिस yaml-rust पर निर्भर था, उसमें मूल लेखक की रुचि कम होने के बाद feature requests और bugs जमा होते गए थे
  • RUSTSEC में दर्ज होने के बाद direct और indirect users के CI fail होने लगे, और वित्तीय उपमा में इसे downgrade और margin call जैसा कहा जा सकता है
  • alternative libraries या forks भी स्पष्ट समाधान नहीं थे, क्योंकि dependency बदलने पर भी maintenance burden और नई dependency risk बनी रहती है
  • अंतिम प्रतिक्रिया yaml-rust कोड को insta के भीतर vendoring करने की थी, और इस पर आलोचना हुई कि यह खराब तकनीकी कर्ज़ को AAA पैकेजिंग में बदल देने वाले CDO जैसा है

yaml-rust dependency के तकनीकी कर्ज़ के रूप में सामने आने की प्रक्रिया

  • insta yaml-rust पर निर्भर था, और मूल लेखक की रुचि खत्म होने के बाद yaml-rust में issues लगातार जमा होते गए थे
    • कुछ feature requests थे, और कुछ वास्तविक bugs थे
    • insta maintainer ने इन समस्याओं का सीधे सामना नहीं किया था, लेकिन maintenance बंद हो चुकी dependency होने के कारण यह तकनीकी कर्ज़ था
  • जब yaml-rust को RUSTSEC database में जोड़ने पर चर्चा शुरू हुई, तो स्थिति बदल गई
    • वित्तीय उपमा में RUSTSEC credit rating agency की भूमिका निभाता है
    • दर्ज होने के बाद yaml-rust को सीधे या परोक्ष रूप से इस्तेमाल करने वाले कई projects का CI कुछ ही मिनटों में fail होने लगा
    • users ने insta maintainer को yaml-rust के इस्तेमाल पर सवाल उठाना शुरू किया, जो वित्तीय उपमा में margin call जैसा था

विकल्प और वास्तविक प्रतिक्रिया

  • किसी alternative पर migrate करना आकर्षक नहीं था
    • एक alternative yaml-rust का fork था, उसका केवल 1 maintainer था, और वह 3 dependencies और जोड़ता था
    • उनमें से एक को पहले से ही “B-” rating मिली हुई थी
    • ecosystem के दूसरे विकल्प ने सवाल उठने से पहले ही default बदलने का फैसला कर लिया था
  • खुद fork करना भी मूल समाधान नहीं था
    • fork की गई लाइब्रेरी के साथ वही maintenance requirements जुड़ी रहतीं
    • अगर bug reports का जवाब न दिया जाए, तो अंततः वही स्थिति बनेगी जैसी yaml-rust के साथ हुई
    • इसलिए fork कुछ समय तो खरीद सकता है, लेकिन समस्या खत्म नहीं करता
  • वास्तविक प्रतिक्रिया yaml-rust कोड को insta के भीतर merge कर देने वाली vendoring थी
    • अब insta, insta code और yaml-rust के मिले-जुले रूप में है
    • यह खराब तकनीकी कर्ज़ को AAA में upgrade करने जैसी संरचना है
    • शीर्षक का CDO 2007 की वित्तीय संकट के दौरान बदनाम हुए Collateralized debt obligation को संदर्भित करता है
  • अंतिम आकलन लगभग यही है कि “कोई नहीं जीता”
    • समस्या वाला code गायब नहीं हुआ, बस insta के भीतर शिफ्ट हो गया
    • बाहरी dependency दिखने पर जो दबाव होता था, वह कम हुआ, लेकिन maintenance burden खुद बना हुआ है

1 टिप्पणियां

 
GN⁺ 2024-03-27
Hacker News टिप्पणियाँ
  • सीधी बात करें तो, सबसे लोकप्रिय YAML parser serde_yaml(https://lib.rs/crates/serde_yaml) के लेखक ने बिना किसी अग्रिम सूचना या उत्तराधिकारी maintainer तय किए अचानक हाथ खींच लिया, और इसे deprecated तथा unmaintained के रूप में चिह्नित कर दिया
    यह left-pad जैसा बिल्कुल नहीं है. पैकेज अब भी काम करता है और crates.io इसे हटाने की अनुमति भी नहीं देता, लेकिन यह पैकेज 4,000 दूसरे crates में इस्तेमाल हो रहा है
    audit और auto-update tools अब unmaintained crates के इस्तेमाल को समस्या के रूप में उठाएँगे

    • यह सही नहीं है. मूल लेख कहता है कि यह yaml-rust(https://github.com/chyh1990/yaml-rust) पर निर्भर करता है, और अब वही project unmaintained हो गया है
      साथ ही, लोगों को बड़ी संख्या में उधर migrate करने से रोकने के लिए serde_yaml को भी unmaintained के रूप में चिह्नित किया गया
    • यहाँ यह लागू नहीं होता, लेकिन बिना dependencies वाली libraries कभी-कभी सचमुच feature-complete होती हैं, इसलिए security fixes के अलावा उन्हें बदलने की लगभग कोई ज़रूरत नहीं होती
      अच्छा होता अगर audit tools और company policies सिर्फ हाल की commits न होने के आधार पर “unmaintained” की चेतावनी देने के बजाय ऐसे मामलों में फर्क कर पातीं
    • क्या वह लेखक Rust library ecosystem में काफ़ी prolific नहीं है? उसने अपनी दूसरी libraries पर ऐसा कदम नहीं उठाया
      जानना चाहूँगा कि क्या इस पर और जानकारी है
  • बिना किसी explanation के आए CDO संक्षेप को मैं तुरंत नहीं समझ पाया, लेकिन लेख में collateralized शब्द कई बार आता है, तो शायद इसका मतलब collateralized debt obligation है
    https://en.wikipedia.org/wiki/Collateralized_debt_obligation
    पहले मेरे दिमाग में chief data officer आया था

    • यहाँ उपमा इस बात की है कि CDO दूसरे कर्ज़ों से बना एक financial product होता है
      खास तौर पर 2008 में यह कई mortgages में fractional ownership जैसी चीज़ थी, और जब खराब mortgages default में गए, तो CDO भी साथ में टूट गए [1]
      वैसे, लेखक जो सोच रहा है वह debt-based metaphor से ज़्यादा leftpad या लगातार होने वाले DNS outages जैसी systemic risk के करीब है. 2008 में इतना बड़ा संकट बनने की बड़ी वजह भी debt को product में बदलना भर नहीं था, बल्कि systemic problems कहीं ज़्यादा बड़ी थीं [2]
      1. दिलचस्प बात यह है कि 2008 से पहले mortgage-based financial products की demand इतनी बढ़ गई थी कि लोगों ने CDO से बने CDO तक बनाने शुरू कर दिए थे. बिना नौकरी वाले लोगों को भी mortgage दिया जाता था, और उसे AAA credit rating वाले product में पैक कर दो तो वह आसानी से बिकने वाला profitable product बन जाता था
      2. इसमें यह भी था कि Lehman और Bear Stearns का leverage ratio 30~40x था. यह पागलपन की हद है
    • सही. निहितार्थ यह है कि अगर खराब technical debt को प्रतिष्ठित packages, यानी AAA packages, में बाँधने के लिए incentives बना दिए जाएँ, तो Rust ecosystem bubble की ओर जा सकता है और अंततः ढह सकता है
      इसका यह मतलब भी है कि regulator जैसी भूमिका निभाने वाली rating agencies पहले ही capture हो चुकी हैं
    • The Big Short देखनी चाहिए. मैंने CDO क्या है, वहीं से सीखा था
    • अभी एहसास हुआ कि अब ऐसी पीढ़ी भी है जो उस दौर की headlines पढ़ने के लिए बहुत छोटी थी जब CDO दुनिया की अर्थव्यवस्था को गिरा रहे थे. खुद को बूढ़ा महसूस कर रहा हूँ
    • मेरे दिमाग में https://en.wikipedia.org/wiki/Collaboration_Data_Objects आया था ;)
  • इसे “जीत” कहना है या नहीं, यह “जीत” की परिभाषा पर बहुत निर्भर करता है, इसलिए उस पर बहस नहीं करना चाहता, लेकिन इसके फ़ायदे स्पष्ट हैं. जो vulnerable code paths न execute होते हैं और न ही external libraries से reachable हैं, वे अब safe code paths बन जाते हैं
    बेशक यह स्थिति चिंताजनक लगती है, लेकिन सुरक्षित तो है
    इस तरह की vendoring का एक और फ़ायदा है. अगर आपकी अपनी library में मज़बूत test coverage है, तो आप नई लाई गई library पर code coverage tools चला सकते हैं
    library को modify करना कठिन हो सकता है, लेकिन आपकी codebase जिन हिस्सों को छूती ही नहीं, उन्हें अपेक्षाकृत आसानी से हटाया जा सकता है. यह structure पर निर्भर करता है, लेकिन अगर vulnerable code पूरी तरह हटा दिया जाए तो यह साफ़ लाभ है, और अगर पता चले कि आप वास्तव में उसका कुछ हिस्सा इस्तेमाल कर रहे थे, तो वह और भी स्पष्ट लाभ हो सकता है
    यानी public maintenance के लिए library को fork करना बड़ी ज़िम्मेदारी है, लेकिन ज़रूरी हिस्सों को vendor करके उनमें बदलाव करना कहीं छोटा बोझ है. भले आप वास्तव में pruning न करें, सिर्फ यह तथ्य कि वह आसान हो जाता है, अपने आप में प्रगति है
    नुकसान भी साफ़ हैं, लेकिन सब कुछ बुरा नहीं है

    • वास्तव में यह बहुत अच्छा नतीजा है. हर dependency एक security risk है, और सभी dependencies को vendor न करने के पक्ष में तर्क यह होता है कि ज्ञात security issues से बचने के लिए external dependencies को up to date रखना चाहिए
      लेकिन अगर external dependency पर अब कोई नज़र रखने वाला ही न हो, तो वह तर्क खत्म हो जाता है, और वह dependency बोझ बन जाती है
      dependency को abandoned के रूप में चिह्नित किया जाना और security reports में दिखना वही व्यवहार है जो हम चाहते हैं. इससे आप जानकारी के आधार पर तय कर सकते हैं कि vendoring करनी है, यानी “कोई malicious actor चुपके से कुछ घुसा दे” वाले जोखिम को हटाना है, या कोई और विकल्प चुनना है
      यह भी अच्छी बात है कि Rust build system इसे आसानी से संभव बनाता है
    • यह भी उल्लेखनीय है कि Google में policy के तहत सभी third-party dependencies को vendor करना पड़ता है
      आम तौर पर पूरे विशाल monorepo में उस dependency का सिर्फ एक version अनुमति पाता है. हो सकता है मेरे वहाँ होने के बाद यह बदल गया हो
      और हर third_party dependency के लिए एक designated owner या OWNERS होते हैं
      इससे चीज़ें काफ़ी हद तक व्यवस्थित रहती हैं
      हालाँकि, ऐसी enforced discipline Google जैसे संगठनों में ठीक बैठ सकती है, जहाँ समय और पैसा पर्याप्त हो और जो “move fast and break things” वाली philosophy से बँधे न हों. startups में यह कितना कारगर होगा, पता नहीं
    • सोचता हूँ क्या library maintainers के लिए अपनी library की transitive code coverage निकालने वाला कोई tool है, जैसे यह गणना करना कि किन दूसरी libraries के test suites उनकी library का उपयोग करते हैं
      एक अर्थ में, दूसरी libraries लगभग यादृच्छिक calls उपलब्ध कराने वाले directed fuzz tests जैसी होती हैं, इसलिए यह एक दिलचस्प testing strategy हो सकती है
  • JS npm ecosystem में भी यही pattern देखा गया है
    npm audit सुरक्षा समस्याओं में अक्सर झूठा अलार्म साबित होता है, और अगर license अनुमति देता हो तो code को अपने अंदर ले आना, users के नकली issues से दबे बिना निपटने के सबसे स्थिर तरीकों में से एक है
    अक्सर users context नहीं समझते, या उनके employer की policy ऐसी जगह बनाई गई होती है जो वास्तविकता से कटी हुई होती है, इसलिए वे इसे नज़रअंदाज़ नहीं कर सकते
    build pipeline की transitive dependency codebase के किसी हिस्से में इस्तेमाल होने वाला regex वास्तव में denial-of-service attack के लिए exploit किया जा सके, ऐसा ज़रूरी नहीं है
    गहरी transitive dependency के “issues” से बचना खास तौर पर झंझटभरा हो सकता है। संरचना के कारण अक्सर यह तकनीकी रूप से साबित करना मुश्किल होता है कि “हम कभी उस code path में जाते ही नहीं, इसलिए defect का असर हम पर नहीं पड़ता” या “उस path में जाने का एकमात्र मामला offline environment में trusted input है”

    • JS दुनिया में development dependencies के issues सचमुच सिरदर्द हैं
      ऐसे scenarios मौजूद हैं जहाँ यह समस्या महत्वपूर्ण होती है। उदाहरण के लिए, compromised build tool build हो रही library में malicious code inject कर सकता है
      लेकिन ऐसे मामले बहुत दुर्लभ हैं, और build के दौरान सिर्फ call किए जाने वाले, पर वास्तव में महत्वहीन denial-of-service वाले regex की बाढ़ में दब जाते हैं
      ऊपर से सामान्य build tools की dependency tree में लगभग 50 अरब transitive dependencies जैसी स्थिति जुड़ जाए तो यह वाकई बहुत कठिन काम बन जाता है
      मेरा मानना है कि ऐसे issues report करने वाले tools को “redistribute करने पर exploit हो सकता है” और “build pipeline में इस्तेमाल करने पर exploit हो सकता है” के बीच फर्क करना चाहिए
    • भले ही अभी उस problem path में प्रवेश न होता हो, बाद में dependency update होने पर problem path में प्रवेश होने लग सकता है
  • “अब घटिया technical debt अचानक AAA grade बन गया” में “अचानक” का मतलब शायद यह है कि सिर्फ वही code vendoring होने की वजह से पहले से बेहतर debt grade पा जाए, यह तर्कसंगत नहीं लगता
    लेकिन वह code के अपने मूल्य तक ही सीमित नज़र है, और पूरी value proposition के सबसे महत्वपूर्ण हिस्से को छोड़ देती है
    अगर maintainer code को अपने अंदर ले आता है, तो अब वह code उसी maintainer का हो जाता है। अगर किसी dead project का code किसी active maintainer द्वारा vendor किया जाता है, तो उस code की value बढ़ जाती है, क्योंकि अब कोई active person मौजूद है जो issue पर प्रतिक्रिया दे सकता है, pull request review कर सकता है, और bug fix कर सकता है
    एक और उपमा लें तो यह ऐसा है जैसे उपेक्षित पालतू जानवर को नए मालिक के पास भेजना; बेहतर देखभाल मिलने से वह ज़्यादा स्वस्थ रह सकता है, लंबा जी सकता है, और उसकी value बढ़ जाती है

    • यह सिर्फ उन लोगों पर लागू होता है जो उस dependency का परोक्ष रूप से उपयोग करते हैं। इस मामले में bug ढूँढने के लिए देखने वाली निगाहें बहुत कम होने की संभावना है
      maintainer को भी बड़े और अपरिचित codebase के साथ अभ्यस्त होना पड़ेगा, इसलिए fix implement करने या review करने में entry barrier होगा
  • थोड़ा side note और विवादास्पद विचार है, लेकिन मेरा मानना है कि अगर source-based package manager, प्रकाशित package के maintenance को registry द्वारा जबरन अपने हाथ में लेने का कानूनी अधिकार सुनिश्चित नहीं करते, तो भयानक समस्याओं से बचना मुश्किल है
    जैसे abandonment, malicious changes, malicious removal, और impersonation
    अगर किसी package को बड़े community के लिए पर्याप्त रूप से महत्वपूर्ण माना जाए, तो package registry entry को उसके मूल मालिक से छीनकर fork की ओर point कराने का कोई तरीका होना चाहिए
    स्वाभाविक है कि ऐसे कदम के साथ बहुत drama होगा, लेकिन इससे downstream users की सक्रिय रूप से रक्षा की जा सकती है

    • यह मुझे बहुत बड़ी समस्या नहीं लगती। open source की खूबसूरती ही fork कर सकने में है
      असली समस्या यह है कि open source project को maintain करने में समय और मेहनत लगती है, और खाली समय रखने वाला कोई दूसरा व्यक्ति आसानी से मिल नहीं जाता
    • जिस source-based package manager में registry ज़रूरत समझे तो package ownership छीन सकती है, उसे contributions आकर्षित करने में मुश्किल होनी चाहिए
      यह उस copyright model से भी कम आकर्षक है जहाँ हर contribution अपने-आप किसी खास समूह की मिल्कियत बन जाती है
      यह तर्क दिया जा सकता है कि GitHub free software host करते हुए उस software के copyright infringement के लिए विशेष रूप से अनुकूल जगह है, लेकिन कम से कम फिलहाल वह package की नाममात्र ownership छीनने की कोशिश तो नहीं करता
    • अगर बात community स्तर पर महत्व की है, तो यह ज़्यादा से ज़्यादा package स्तर का काम है, registry स्तर का नहीं
      क्योंकि यह community की बात है, ग्राहक-आपूर्तिकर्ता संबंध नहीं, और अधिकतर packages उतने ही महत्वपूर्ण होते हैं जितना कि उनका मुफ़्त में उपलब्ध होना
      यह “हम तुम्हें 10 डॉलर प्रति माह देंगे, बस हमारे लिए 100000 packages manage कर लो” जैसी अपमानजनक रकम भी बन सकती है
    • ये सारी समस्याएँ एक ही तरह की नहीं हैं। frozen package का मतलब सिर्फ इतना है कि downstream dependencies को फैसला लेना होगा, लेकिन vendoring सहित विकल्प काफ़ी हैं
      इंटरनेट पर unmanaged source code बहुत है, और अक्सर वह बस एक बार जैसा है वैसा प्रकाशित कर दिया गया है। मुफ़्त code के लिए किसी को updates की गारंटी नहीं मिलती
    • विकल्प है Kik NPM समस्या। किसी भी तरफ जाएँ, बुरा ही है
  • यह काफ़ी सौभाग्यशाली बात थी कि किसी ने पहले ही yaml-rust को fork करके yaml-rust2(https://github.com/Ethiraric/yaml-rust2/blob/master/document...) बना लिया था
    यह भी बढ़िया है कि वह fork YAML test suite पूरी तरह pass करता है, benchmark में भी तेज़ है, और migration भी आसान लगती है
    फिर भी मूल समस्या बनी रहती है। हम अभी ऐसे लोगों के काम पर निर्भर हैं जो खुशी-खुशी मुफ़्त श्रम दे रहे हैं, लेकिन यह ज़रूरी नहीं कि वह हमेशा चलता रहे
    मुझे नहीं पता कि उनके समय और मेहनत का प्रतिफल देने और उनसे अच्छे काम को जारी रखने की उम्मीद करने के अलावा कोई दूसरा रास्ता है भी या नहीं

    • yaml-rust मूल रूप से शुद्ध Rust implementation था, और tagline में यह बात शाब्दिक रूप से लिखी भी थी
      “A pure rust YAML implementation.”
      बल्कि serde_yaml को pure Rust कहना और भी मुश्किल था, क्योंकि वह libyaml के c2rust-converted रूप unsafe-libyaml पर निर्भर था
    • bus factor 1 वाले projects स्वभावतः जोखिमभरे होते हैं
      पर्याप्त लंबे समय-पैमाने पर open source maintainer के project छोड़ देने की संभावना 1 होती है
      इससे बचने का एकमात्र तरीका यह है कि एकल-maintainer projects को वर्जित माना जाए
    • इस समस्या के लिए मेरा मूल समाधान है कि जहाँ तक संभव हो third-party dependencies से बचा जाए
      Rust standard library बनाने वाले लोग standard library को सीमित रखना चाहते हैं, इसलिए Rust projects में शायद यह विकल्प न हो
      लेकिन दूसरी भाषाओं में, जहाँ standard library पर्याप्त रूप से सक्षम हो, यह स्पष्ट रूप से संभव विकल्प है
      मैं जानबूझकर ऐसी भाषाएँ इस्तेमाल करता हूँ जिनमें ज़रूरी चीज़ें built-in हों, इसलिए database driver के अलावा मैं लगभग कोई बाहरी library इस्तेमाल नहीं करता
  • यह पूरी स्थिति थोड़ी हास्यास्पद लगती है। अगर कोड काम करता है और सालों से करता आ रहा है, तो मुझे समझ नहीं आता कि उसका maintain न होना समस्या क्यों है
    अगर उसे बदलने की ज़रूरत नहीं है और उसकी सीमाएँ व फीचर्स पता हैं, तो वह ठीक है
    कोड अपने-आप खराब नहीं हो जाता। मैंने कई बार दशकों पुराने कोड को उधार लेकर या integrate करके अच्छे से इस्तेमाल किया है
    व्यक्तिगत रूप से, मैं शायद उस लाइब्रेरी के बारे में सारी शिकायतों को बस नज़रअंदाज़ करके आगे बढ़ जाता

    • स्पष्ट जवाब यह है कि वह कई मायनों में “काम” नहीं करती
      पहले से बहुत सारे bugs जमा हो चुके हैं, और fixes मौजूद होने के बावजूद कभी patch नहीं किए जाएंगे। https://github.com/chyh1990/yaml-rust/issues और /pulls देख लें
    • दशकों पुराने कोड को उधार लेने या integrate करने से आपका मतलब क्या वही नहीं है जो लेखक ने लाइब्रेरी को अपने प्रोजेक्ट में vendor करके किया?
      यानी आप उस कोड के हिस्से के maintenance की ज़िम्मेदारी अपने ऊपर ले रहे हैं जिसका आप इस्तेमाल करते हैं
      कभी-कभी यह बुरा हो सकता है। यह copy-paste coding या duplicated effort बन सकता है
      लेकिन अगर third-party component पूरी तरह unmaintained हो, तो यह काफ़ी समझ में आने वाली बात है
  • सही है, dependencies को vendor कर लेना चाहिए। जो dependencies “लगभग पूरी” हों और जिनका development व maintenance धीमा पड़ गया हो, उनके साथ पिछले 20 सालों में मैंने ज़्यादातर यही किया है
    हालांकि, मैंने कभी ऐसी language में काम नहीं किया जहाँ “batteries are not included” हो

  • क्या cargo vendor --aggressive जैसा कुछ हो सकता है, ताकि मेरे crate के हिसाब से dependency के अंदर का सारा dead code prune किया जा सके?
    सोच रहा हूँ कि क्या इससे “dependencies को review करो” वाली समस्या को ज़्यादा संभालने लायक बनाया जा सकता है
    यह लेख के मुख्य बिंदु से थोड़ा हटकर है, लेकिन इस मायने में जुड़ा हुआ भी है कि dependency चुनने और उससे जुड़ी सारी ज़िम्मेदारियाँ आख़िरकार हमारी ही होती हैं
    ऐसा लगता है कि ऐसे tools के लिए जगह है जो हमें इस बात के प्रति ज़्यादा ज़िम्मेदार बनने में मदद करें कि वास्तव में crate में compile होकर क्या शामिल हो रहा है

    • तो क्या फिर आप लाइब्रेरी की सारी bug reports भी अपने bug tracker में कॉपी करके लाते हैं?
      अगर नहीं, तो मुझे समझ नहीं आता कि इससे बेहतर क्या होता है