
tailsnitch v1.7
Tailscale कॉन्फ़िगरेशन के लिए एक सुरक्षा ऑडिटर। आपके टेलनेट में गलत कॉन्फ़िगरेशन, अत्यधिक अनुमति वाले एक्सेस कंट्रोल और सुरक्षा सर्वोत्तम प्रथाओं के उल्लंघनों को स्कैन करता है।
Tailsnitch
Tailscale कॉन्फ़िगरेशन के लिए एक सुरक्षा ऑडिटर। Tailsnitch आपके tailnet को 57 मिसकॉन्फ़िगरेशन, अत्यधिक अनुमतिपूर्ण एक्सेस नियंत्रण, और सुरक्षा सर्वोत्तम अभ्यास उल्लंघनों के लिए स्कैन करता है।
त्वरित आरंभ
# 1. अपनी Tailscale API क्रेडेंशियल सेट करें
export TS_API_KEY="tskey-api-..."
# 2. ऑडिट चलाएँ
tailsnitch
# 3. केवल उच्च-गंभीरता वाले निष्कर्ष देखें
tailsnitch --severity high
# 4. कुछ समस्याओं को ठीक करें ~इंटरैक्टिवली~ yolo मोड
tailsnitch --fix
स्थापना
पूर्व-निर्मित बाइनरी डाउनलोड करें
GitHub Releases से नवीनतम रिलीज़ डाउनलोड करें।
macOS उपयोगकर्ता: डाउनलोड के बाद quarantine विशेषता हटाएँ:
sudo xattr -rd com.apple.quarantine tailsnitch
Go के माध्यम से स्थापित करें
go install github.com/Adversis/tailsnitch@latest
स्रोत से निर्माण करें
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
प्रमाणीकरण
Tailsnitch दो प्रमाणीकरण विधियों का समर्थन करता है। जब दोनों कॉन्फ़िगर किए जाते हैं तो OAuth को प्राथमिकता दी जाती है।
विकल्प 1: OAuth क्लाइंट (अनुशंसित)
OAuth क्लाइंट स्कोप्ड, ऑडिटेबल एक्सेस प्रदान करते हैं जो कर्मचारियों के जाने पर समाप्त नहीं होता।
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
OAuth क्लाइंट यहाँ बनाएँ: https://login.tailscale.com/admin/settings/oauth
रीड-ओनली ऑडिट के लिए आवश्यक स्कोप:
all:read सब कुछ कवर करता है। स्कोप को व्यक्तिगत रूप से प्रदान करना:
| स्कोप | किसके लिए उपयोग किया जाता है |
|---|---|
policy_file:read | Tailnet नीति फ़ाइल — ACL-, NET-, SSH-* |
devices:core:read | डिवाइस सूची — DEV-, NET-, ACL-011 |
dns:read | DNS कॉन्फ़िगरेशन — DNS-001, DEV-007 |
auth_keys:read | मशीन प्रमाणीकरण कुंजियाँ — AUTH-*, ACL-011 |
feature_settings:read | Tailnet सेटिंग्स — DEV-008, DEV-009, DEV-014 |
logs:network:read | नेटवर्क फ़्लो लॉगिंग सेटिंग — LOG-001 |
networking_settings:read | HTTPS प्रमाणपत्र सेटिंग — NET-004 |
log_streaming:read | लॉग स्ट्रीम गंतव्य — LOG-002 |
webhooks:read | Webhook एंडपॉइंट — LOG-005, LOG-012 |
oauth_keys:read | OAuth क्लाइंट — LOG-006 |
users:read | उपयोगकर्ता भूमिकाएँ और स्थिति — USER-001, LOG-006 |
account_settings:read | सुरक्षा संपर्क — LOG-011 |
devices:posture_attributes:read | Posture एकीकरण — DEV-014 |
आप जो भी स्कोप छोड़ते हैं वह केवल उन जाँचों को प्रभावित करता है जिन्हें उसकी आवश्यकता होती है: वे जाँचें पास होने के बजाय रिपोर्ट करती हैं कि वे सेटिंग नहीं पढ़ सकीं।
AUTH-005 और AUTH-006 tailnet की federated पहचान पढ़ते हैं, जिसे एडमिन कंसोल trust credentials कहता है। वे auth keys के समान कुंजी सूची से आते हैं, इसलिए auth_keys:read उन्हें कवर करने की उम्मीद है। यह एक लाइव tailnet के विरुद्ध पुष्टि नहीं किया गया है। यदि कुंजी सूची नहीं पढ़ी जा सकती है, तो दोनों जाँचें पास होने के बजाय not evaluated रिपोर्ट करती हैं। क्या एक लापता स्कोप त्रुटि लौटाता है या इसके बजाय पहचान को फ़िल्टर करके सूची लौटाता है, यह अपुष्ट है; यदि यह चुपचाप फ़िल्टर करता है, तो AUTH-005 रिपोर्ट करेगा कि कोई trust credentials मौजूद नहीं हैं और AUTH-006 को जाँचने के लिए कुछ नहीं मिलेगा।
फिक्स मोड के लिए अतिरिक्त स्कोप:
devices:core- डिवाइस हटाएँ, टैग संशोधित करें (टैग चयन की आवश्यकता है)auth_keys- प्रमाणीकरण कुंजियाँ हटाएँ
Tailnet Lock
DEV-010 और DEV-012 Tailnet Lock पर रिपोर्ट करते हैं, जिसे Tailscale API tailnet सेटिंग के रूप में उजागर नहीं करता। इसके द्वारा लॉक किए गए डिवाइस API के माध्यम से दिखाई देते हैं, लेकिन यह निर्धारित करना कि lock सक्षम है या नहीं, स्थानीय tailscale CLI की आवश्यकता होती है, जो tailsnitch चलाने वाली मशीन पर daemon पढ़ता है। --tailnet के साथ किसी अन्य tailnet का ऑडिट करते समय, परिणाम के उस भाग को तदनुसार मानें। यदि बाइनरी एक गैर-मानक स्थान में है तो --tailscale-path का उपयोग करें।
विकल्प 2: API कुंजी
API कुंजियाँ उस उपयोगकर्ता के रूप में कार्य करती हैं जिसने उन्हें बनाया है और उस उपयोगकर्ता की अनुमतियाँ विरासत में लेती हैं।
export TS_API_KEY="tskey-api-..."
API कुंजी यहाँ बनाएँ: https://login.tailscale.com/admin/settings/keys
उपयोग उदाहरण
बुनियादी ऑडिट
# पूर्ण ऑडिट चलाएँ
tailsnitch
# पास होने वाली जाँचें भी दिखाएँ (verbose)
tailsnitch --verbose
# प्रोसेसिंग के लिए JSON के रूप में आउटपुट
tailsnitch --json
# एक विशिष्ट tailnet का ऑडिट करें (जब OAuth क्लाइंट के पास कई तक पहुँच हो)
tailsnitch --tailnet mycompany.com
परिणाम फ़िल्टर करें
# केवल क्रिटिकल और उच्च गंभीरता वाली समस्याएँ दिखाएँ
tailsnitch --severity high
# श्रेणी के अनुसार फ़िल्टर करें
tailsnitch --category access # ACL समस्याएँ
tailsnitch --category auth # प्रमाणीकरण और कुंजियाँ
tailsnitch --category device # डिवाइस सुरक्षा
tailsnitch --category network # नेटवर्क एक्सपोज़र
tailsnitch --category ssh # SSH नियम
tailsnitch --category log # लॉगिंग और एडमिन
# केवल विशिष्ट जाँचें चलाएँ
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# सभी उपलब्ध जाँचें सूचीबद्ध करें
tailsnitch --list-checks
इंटरैक्टिव फिक्स मोड
फिक्स मोड आपको Tailscale API के माध्यम से सीधे समस्याओं को ठीक करने की अनुमति देता है:
# इंटरैक्टिव फिक्स मोड
tailsnitch --fix
# पूर्वावलोकन करें कि क्या ठीक किया जाएगा (dry run)
tailsnitch --fix --dry-run
# सुरक्षित फिक्स स्वतः चुनें (अभी भी पुष्टि की आवश्यकता है)
tailsnitch --fix --auto
# फिक्स क्रियाओं की ऑडिट लॉगिंग अक्षम करें
tailsnitch --fix --no-audit-log
API-फिक्सेबल आइटम:
| जाँच | क्रिया |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | प्रमाणीकरण कुंजियाँ हटाएँ |
| DEV-002 | उपयोगकर्ता डिवाइसों से टैग हटाएँ |
| DEV-004 | पुराने डिवाइस हटाएँ |
| DEV-005 | लंबित डिवाइस अधिकृत करें |
फिक्स मोड उन समस्याओं के लिए एडमिन कंसोल के सीधे लिंक भी प्रदान करता है जिनके लिए मैन्युअल हस्तक्षेप की आवश्यकता होती है।
SOC 2 साक्ष्य निर्यात
Common Criteria (CC) नियंत्रण मैपिंग के साथ SOC 2 ऑडिट के लिए साक्ष्य रिपोर्ट उत्पन्न करें:
# JSON के रूप में निर्यात करें
tailsnitch --soc2 json > soc2-evidence.json
# CSV के रूप में निर्यात करें (स्प्रेडशीट के लिए)
tailsnitch --soc2 csv > soc2-evidence.csv
SOC 2 रिपोर्ट में शामिल हैं:
- प्रति-संसाधन परीक्षण परिणाम (प्रत्येक डिवाइस, कुंजी, ACL नियम व्यक्तिगत रूप से परीक्षण किया गया)
- CC कोड मैपिंग (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2, आदि)
- प्रत्येक नियंत्रण परीक्षण के लिए पास/फेल/एन/ए स्थिति
- ऑडिट ट्रेल के लिए टाइमस्टैम्प
उदाहरण CSV आउटपुट:
resource_type,resource_id,resource_name,check_id,check_title,cc_codes,status,details,tested_at
device,node123,prod-server,DEV-001,Tagged devices with key expiry disabled,CC6.1;CC6.3,PASS,Tags: [tag:server] key expiry enabled,2025-01-05T10:30:00Z
key,tskey-auth-xxx,tskey-auth-xxx,AUTH-001,Reusable auth keys exist,CC6.1;CC6.2;CC6.3,FAIL,Reusable key expires in 45 days,2025-01-05T10:30:00Z
ज्ञात जोखिमों को अनदेखा करें
ज्ञात-स्वीकृत जोखिमों के लिए निष्कर्ष दबाने हेतु एक .tailsnitch-ignore फ़ाइल बनाएँ:
# .tailsnitch-ignore
# सूचनात्मक जाँचें अनदेखा करें
ACL-008 # हम जानबूझकर समूहों का उपयोग नहीं करते
ACL-009 # लीगेसी ACL हमारे उपयोग के लिए ठीक हैं
# औचित्य के साथ विशिष्ट मध्यम जाँचें अनदेखा करें
DEV-006 # बाहरी डिवाइस स्वीकृत ठेकेदार हैं
LOG-001 # फ़्लो लॉग के लिए Enterprise योजना आवश्यक है
# पूरी जाँच को म्यूट करने के बजाय एक जाँच के भीतर एक आइटम अनदेखा करें
ACL-011:tag:monitoring # डिज़ाइन से व्यापक; हर अन्य टैग अभी भी जाँचा जाता है
AUTH-001:tskey-auth-xxxx # CI के माध्यम से स्वचालित रूप से घूमता है, TICKET-123 में ट्रैक किया गया
एक पंक्ति या तो एक पूरी जाँच (ACL-011) या उसके भीतर एक आइटम नाम देती है
(CHECK-ID:item, पहले कोलन पर विभाजित - आइटम में स्वयं कोलन हो सकते हैं)।
एक प्रति-आइटम नियम केवल उस आइटम को दबाता है: जाँच अभी भी चलती है और
अभी भी बाकी सब कुछ रिपोर्ट करती है जो वह पाती है। हर फ़्लैग किए गए आइटम को दबाना
कभी भी एक असफल जाँच को पास होने वाली जाँच में नहीं बदलता - निष्कर्ष बना रहता है,
Informational तक डाउनग्रेड किया जाता है, इसलिए एक दबाया गया निष्कर्ष कभी भी संतुष्ट नियंत्रण के रूप में नहीं पढ़ा जाता।
अनदेखा फ़ाइल स्थान (क्रम में जाँचे गए):
- वर्तमान निर्देशिका में
.tailsnitch-ignore - होम निर्देशिका में
~/.tailsnitch-ignore
क्योंकि पहला स्थान कार्यशील निर्देशिका है, एक अनदेखा फ़ाइल आपके बजाय
एक रिपॉज़िटरी से आ सकती है। हर रन रिपोर्ट करता है कि उसने कौन सी फ़ाइल उपयोग की
और उसने कितने निष्कर्ष और आइटम दबाए, और --json इसे
ignore_file और ignored फ़ील्ड में रिकॉर्ड करता है (CHECK-ID एक पूरी जाँच के लिए,
CHECK-ID:item एक दबाए गए आइटम के लिए)। फ़ाइल को छोड़ने के लिए --no-ignore का उपयोग करें।
# एक विशिष्ट अनदेखा फ़ाइल का उपयोग करें
tailsnitch --ignore-file /path/to/ignore
# अनदेखा फ़ाइल प्रोसेसिंग पूरी तरह से अक्षम करें
tailsnitch --no-ignore
JSON निर्यात और प्रोसेसिंग
# पूर्ण रिपोर्ट निर्यात करें
tailsnitch --json > audit.json
# असफल जाँचें TSV के रूप में निकालें
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# गंभीरता के अनुसार सारांश
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# एडमिन लिंक के साथ क्रिटिकल/उच्च समस्याएँ सूचीबद्ध करें
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
कमांड संदर्भ
| फ़्लैग | विवरण |
|---|---|
--json | JSON के रूप में आउटपुट |
--severity | न्यूनतम गंभीरता से फ़िल्टर करें: critical, high, medium, low, info |
--category | श्रेणी से फ़िल्टर करें: access, auth, network, ssh, log, device, dns |
--checks | विशिष्ट जाँचें चलाएँ (अल्पविराम-पृथक IDs या slugs) |
--list-checks | सभी उपलब्ध जाँचें सूचीबद्ध करें और बाहर निकलें |
--tailnet | ऑडिट करने के लिए tailnet निर्दिष्ट करें (डिफ़ॉल्ट: API कुंजी से) |
--verbose | पास होने वाली जाँचें भी दिखाएँ |
--fix | इंटरैक्टिव फिक्स मोड सक्षम करें |
--auto | सुरक्षित फिक्स स्वतः चुनें (--fix की आवश्यकता है) |
--dry-run | निष्पादित किए बिना फिक्स क्रियाओं का पूर्वावलोकन करें (--fix की आवश्यकता है) |
--no-audit-log | फिक्स क्रियाओं की ऑडिट लॉगिंग अक्षम करें |
--soc2 | SOC 2 साक्ष्य निर्यात करें: json या csv |
--tailscale-path | tailscale CLI का पथ (Tailnet Lock जाँचों के लिए) |
--timeout | ऑडिट के लिए कुल समय बजट (डिफ़ॉल्ट 2m) |
--ignore-file | अनदेखा फ़ाइल का पथ |
--no-ignore | अनदेखा फ़ाइल प्रोसेसिंग अक्षम करें |
--version | संस्करण जानकारी दिखाएँ |
सुरक्षा जाँचें
Tailsnitch 7 श्रेणियों में 57 सुरक्षा जाँचें करता है। प्रत्येक जाँच के विस्तृत दस्तावेज़ीकरण के लिए docs/CHECKS.md देखें।
क्रिटिकल गंभीरता
| ID | जाँच | जोखिम |
|---|---|---|
| ACL-001 | डिफ़ॉल्ट 'allow all' नीति | सभी डिवाइसों के पास अप्रतिबंधित पहुँच है |
| ACL-002 | SSH autogroup:nonroot मिसकॉन्फ़िगरेशन | किसी भी गैर-root उपयोगकर्ता के रूप में SSH |
| ACL-006 | tagOwners बहुत व्यापक | टैग के माध्यम से विशेषाधिकार वृद्धि |
| ACL-007 | autogroup:danger-all उपयोग | बाहरी उपयोगकर्ताओं को पहुँच प्रदान की गई |
उच्च गंभीरता
| ID | जाँच | जोखिम |
|---|---|---|
| ACL-011 | टैग पहुँच एक विश्वास सीमा पार करती है | एक चोरी की गई पुन: प्रयोज्य कुंजी एक टैग बनाती है जो सब कुछ तक पहुँचती है |
| AUTH-001 | पुन: प्रयोज्य प्रमाणीकरण कुंजियाँ | चोरी होने पर असीमित डिवाइस जोड़ |
| AUTH-002 | लंबी समाप्ति वाली प्रमाणीकरण कुंजियाँ | विस्तारित एक्सपोज़र विंडो |
| AUTH-003 | पूर्व-अधिकृत कुंजियाँ | डिवाइस अनुमोदन को बायपास करें |
| AUTH-006 | Federated पहचान विषय बहुत व्यापक | जारीकर्ता द्वारा प्रमाणित कोई भी प्रिंसिपल टैग बना सकता है |
| DEV-001 | कुंजी समाप्ति के बिना टैग किए गए डिवाइस | अनिश्चितकालीन पहुँच |
| DEV-002 | उपयोगकर्ता डिवाइस टैग किए गए | उपयोगकर्ता हटाने के बाद बने रहते हैं |
| DEV-010 | Tailnet Lock अक्षम | चोरी की गई कुंजियों के विरुद्ध कोई सुरक्षा नहीं |
| DEV-012 | लंबित Tailnet Lock हस्ताक्षर | अहस्ताक्षरित नोड्स को समीक्षा की आवश्यकता है |
| NET-001 | Funnel एक्सपोज़र | सार्वजनिक इंटरनेट पहुँच |
| NET-003 | सबनेट राउटर विश्वास सीमा | स्थानीय नेटवर्क पर अनएन्क्रिप्टेड ट्रैफ़िक |
| SSH-002 | चेक मोड के बिना root SSH | पुनः-प्रमाणीकरण की आवश्यकता नहीं |
मध्यम गंभीरता
| ID | जाँच | जोखिम |
|---|---|---|
| ACL-004 | autogroup:member उपयोग | बाहरी उपयोगकर्ता शामिल |
| ACL-005 | AutoApprovers कॉन्फ़िगर किया गया | रूट अनुमोदन को बायपास करें |
| AUTH-004 | गैर-ephemeral CI/CD कुंजियाँ | पुराने डिवाइस जमा होते हैं |
| AUTH-005 | कार्यभार पहचान federation उपयोग में नहीं | लंबे समय तक चलने वाली कुंजियाँ चोरी योग्य रहती हैं |
| DEV-003 | पुराने क्लाइंट | संभावित कमजोरियाँ |
| DEV-004 | पुराने डिवाइस | अप्रयुक्त हमले की सतह |
| DEV-005 | अनधिकृत डिवाइस | लंबित अनुमोदन कतार |
| DEV-007 | संवेदनशील मशीन नाम | CT लॉग एक्सपोज़र |
| DEV-009 | डिवाइस अनुमोदन कॉन्फ़िगरेशन | सक्षम नहीं हो सकता |
| NET-004 | HTTPS CT लॉग एक्सपोज़र | मशीन नाम सार्वजनिक |
| NET-005 | Exit नोड ट्रैफ़िक दृश्यता | ऑपरेटर सभी ट्रैफ़िक देखता है |
| NET-006 | Serve एक्सपोज़र | tailnet पर स्थानीय सेवाएँ |
| SSH-003 | Recorder UI एक्सपोज़र | सत्र नेटवर्क को दिखाई देते हैं |
सूचनात्मक
लॉगिंग कॉन्फ़िगरेशन, DNS सेटिंग्स, उपयोगकर्ता भूमिकाओं और मैन्युअल सत्यापन आइटमों के लिए जाँचें।
गंभीरता जो निष्कर्ष पर निर्भर करती है
कई जाँचें एक निश्चित गंभीरता रखने के बजाय जो पाती हैं उसे रेट करती हैं। यहाँ तीन उल्लेखनीय हैं:
- ACL-011 हर टैग की पहुँच को Informational पर रिपोर्ट करता है। यह केवल तब विफल होता है जब एक प्रमाणीकरण कुंजी जो टैग असाइन कर सकती है, एक वाइल्डकार्ड गंतव्य, एक रूटेड सबनेट या exit-node egress तक पहुँचती है: High यदि एक पुन: प्रयोज्य कुंजी उस टैग को असाइन करती है, Medium यदि केवल एक एक-बार की कुंजी करती है। एक डिवाइस गिनती कभी गंभीरता निर्धारित नहीं करती।
- AUTH-005 Medium रिपोर्ट करता है जब tailnet में कोई trust credentials नहीं होते, और Low जब trust credentials मौजूद होते हैं लेकिन एक पुन: प्रयोज्य कुंजी अभी भी ऐसे टैग बनाती है जिन्हें उनमें से कोई कवर नहीं करता।
- AUTH-006 एक विषय के लिए High रिपोर्ट करता है जो केवल एक वाइल्डकार्ड है, और एक संकीर्ण वाइल्डकार्ड या एक लापता audience के लिए Low।
आउटपुट उदाहरण
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.0.0 (build: abc123) |
+=====================================================================+
Using ignore file: .tailsnitch-ignore (3 rules)
=== ACCESS CONTROLS ===================================================
[CRITICAL] ACL-001: Default 'allow all' policy active
Your ACL policy omits the 'acls' field. Tailscale applies a
default 'allow all' policy, granting all devices full access.
Remediation:
Define explicit ACL rules following least privilege principle.
Source: https://tailscale.com/docs/reference/examples/acls
----------------------------------------------------------------------
=== AUTHENTICATION & KEYS =============================================
[HIGH] AUTH-001: Reusable auth keys exist
Found 2 reusable auth key(s). These can be reused to add
multiple devices if compromised.
Details:
- Key tskey-auth-xxx (expires in 45 days)
- Key tskey-auth-yyy (expires in 89 days)
Remediation:
Store reusable keys in a secrets manager. Prefer one-off keys.
Source: https://tailscale.com/docs/features/access-control/auth-keys
----------------------------------------------------------------------
SUMMARY
======================================================================
Critical: 1 High: 3 Medium: 5 Low: 2 Info: 8
Total findings: 19 | Passed: 33
Tailnet Lock जाँचें
Tailnet Lock जाँचें (DEV-010, DEV-012) स्थानीय tailscale CLI की आवश्यकता होती हैं और स्थानीय मशीन के daemon के विरुद्ध चलती हैं। --tailnet के माध्यम से एक दूरस्थ tailnet का ऑडिट करते समय, ये जाँचें स्थानीय स्थिति को दर्शाती हैं, ऑडिट किए गए tailnet को नहीं।
# आवश्यकता होने पर कस्टम tailscale बाइनरी पथ निर्दिष्ट करें
tailsnitch --tailscale-path /opt/tailscale/bin/tailscale
CI/CD एकीकरण
सुरक्षा प्रतिगमन पकड़ने के लिए CI/CD पाइपलाइनों में Tailsnitch चलाएँ:
# GitHub Actions उदाहरण
- name: Audit Tailscale Security
env:
TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
TS_OAUTH_CLIENT_SECRET: ${{ secrets.TS_OAUTH_CLIENT_SECRET }}
run: |
tailsnitch --json > audit.json
# Fail if critical or high severity issues exist
if tailsnitch --severity high --json | jq -e '.summary.critical + .summary.high > 0' > /dev/null; then
echo "Critical or high severity issues found!"
tailsnitch --severity high
exit 1
fi
संदर्भ
लाइसेंस
MIT
योगदान
दिशानिर्देशों के लिए CONTRIBUTING.md देखें।