GitHub Blog
85

Sản phẩm

Cách GitHub thiết lập quyền sở hữu bền vững cho hàng chục nghìn kho lưu trữ

(giờ Việt Nam)

Tóm tắt AI

GitHub đã thực hiện chiến dịch thần tốc trong 45 ngày để xác thực quyền sở hữu cho hơn 14.000 kho lưu trữ, giúp chuẩn hóa quy trình quản lý và bảo mật hệ thống.

Bản dịch AI

GitHub có hơn 14.000 kho lưu trữ (repository). Chưa đến một nửa trong số đó có quyền sở hữu rõ ràng. Dưới đây là cách chúng tôi xác thực chủ sở hữu cho mọi kho lưu trữ đang hoạt động trong vòng chưa đầy 45 ngày, lưu trữ (archive) các kho còn lại và biến quyền sở hữu thành nền tảng cho mọi công việc sau này.

Ngày 9 tháng 7 năm 2026

9 phút

GitHub có hơn 14.000 kho lưu trữ trên toàn bộ tổ chức GitHub nội bộ chính của chúng tôi. Tính đến đầu năm 2025, có hơn 11.000 kho lưu trữ chưa được lưu trữ, phần lớn trong số đó không có chủ sở hữu rõ ràng. Đối với các kho lưu trữ gắn liền với các dịch vụ sản xuất (production services), chúng tôi luôn duy trì quyền sở hữu bền vững, nhưng với các kho không có dịch vụ liên kết, không có cách nào đáng tin cậy để xác định ai là chủ sở hữu.

Khoảng trống đó đã trở thành một vấn đề tái diễn trong nỗ lực khắc phục quét bí mật (secret scanning) của chúng tôi: mặc dù về mặt kỹ thuật chúng tôi có thể xoay vòng (rotate) một bí mật, nhưng việc thực hiện mà không biết chủ sở hữu kho lưu trữ là rất rủi ro và thường gây gián đoạn, đồng thời chúng tôi không có cách rõ ràng để điều phối công việc khắc phục. Trong vòng một tháng rưỡi, chúng tôi đã xác thực quyền sở hữu cho mọi kho lưu trữ đang hoạt động, lưu trữ khoảng 8.000 kho không còn sử dụng và thay đổi quy trình tạo kho lưu trữ để yêu cầu quyền sở hữu ngay từ đầu.

Mô hình sở hữu ban đầu của chúng tôi

Trong nhiều năm, GitHub đã theo dõi quyền sở hữu đối với các dịch vụ được triển khai thông qua Service Catalog nội bộ. Mỗi mục dịch vụ ghi lại các siêu dữ liệu như kho lưu trữ mà nó nằm trong đó, giúp chúng tôi có sự ánh xạ từ dịch vụ sang kho lưu trữ; nhóm sở hữu; nhà tài trợ điều hành; và thông tin hỗ trợ.

Dưới đây là ví dụ về mục sở hữu dịch vụ của ứng dụng Repo Ownership:

Việc sở hữu siêu dữ liệu phong phú này cho phép các quy trình làm việc tập trung vào dịch vụ, chẳng hạn như phản ứng sự cố, định tuyến trực (on-call routing), quản lý lỗ hổng bảo mật và xác định phạm vi tuân thủ.

Thật không may, mối quan hệ đó là một-nhiều (nghĩa là một dịch vụ chỉ có thể gắn với một kho lưu trữ, nhưng một kho lưu trữ có thể có nhiều dịch vụ). Điều đó có nghĩa là nếu bạn bắt đầu từ một dịch vụ, bạn có thể tìm thấy kho lưu trữ và chủ sở hữu của nó. Nhưng nếu bạn bắt đầu từ một kho lưu trữ và cần tìm chủ sở hữu, bạn phải tra cứu ngược lại, và điều đó chỉ hiệu quả với các kho lưu trữ đã được ánh xạ tới một dịch vụ ngay từ đầu.

Điều đó để lại một khoảng trống sở hữu đáng kể bao gồm các kho lưu trữ của nhóm, kho tài liệu, công cụ nội bộ, kho dự án dùng một lần, kho thử nghiệm cá nhân và bất kỳ thứ gì khác không hỗ trợ một dịch vụ đã triển khai. Mỗi khi cần liên hệ với chủ sở hữu của một trong những kho lưu trữ "vô chủ" này, chúng tôi phải làm thủ công: kiểm tra lịch sử commit, đọc file README, hỏi xung quanh trên Slack hoặc đoán dựa trên tên kho lưu trữ.

Đối với một nỗ lực đơn lẻ, sự mơ hồ đó gây khó chịu nhưng vẫn có thể quản lý được. Đối với các quy trình bảo mật định kỳ lan rộng khắp toàn bộ tổ chức, nó tạo ra một rủi ro thực sự. Trong quá trình dọn dẹp quét bí mật, chúng tôi đã mất quá nhiều thời gian để cố gắng tìm đúng chủ sở hữu trước khi có thể đưa ra các quyết định sáng suốt về các cảnh báo.

Thiết kế mô hình sở hữu mới

Về cơ bản, chúng tôi cần quyền sở hữu kho lưu trữ trở thành một thuộc tính hạng nhất. Chúng tôi đã cân nhắc việc lưu trữ quyền sở hữu trong một tệp chuyên dụng bên trong mỗi kho lưu trữ hoặc duy trì nó trong một kho lưu trữ tập trung, nhưng cuối cùng đã chọn GitHub custom properties. Cách tiếp cận này cung cấp một phương thức quản lý quyền sở hữu tự nhiên, có cấu trúc và có thể truy vấn trên toàn bộ tổ chức. Nó cũng cho phép chúng tôi thực thi các chính sách và quy tắc (rulesets) của doanh nghiệp và tổ chức một cách chọn lọc theo loại hình sở hữu.

Chúng tôi đã tạo hai thuộc tính tùy chỉnh: ownership-type và ownership-name.

Độ bao phủ ngay từ ngày đầu

Trước khi yêu cầu bất kỳ ai làm bất cứ điều gì, chúng tôi đã xây dựng một quy trình đồng bộ định kỳ từ Service Catalog sang các thuộc tính tùy chỉnh của kho lưu trữ. Mọi kho lưu trữ hỗ trợ một dịch vụ đã biết đều được thiết lập ownership-type là “Service Catalog” và ownership-name được điền tự động. Điều đó đã giải quyết được khoảng 1.500 kho lưu trữ có dịch vụ, để lại các kho của nhóm, kho tài liệu, dự án dùng một lần và kho cá nhân.

Triển khai

Để triển khai việc này, chúng tôi đã xây dựng một GitHub App chạy trên Kubernetes CronJob. Logic thực thi cần quyền truy cập vào Service Catalog, GitHub API và một vài hệ thống nội bộ, vì vậy một quy trình GitHub Actions đơn giản là không đủ.

Sơ đồ dưới đây cho thấy luồng thực thi quyền sở hữu kho lưu trữ, từ quá trình quét sở hữu ban đầu đến việc tạo vấn đề cảnh báo, đóng tự động hoặc lưu trữ sau 30 ngày.

Flowchart of repository ownership enforcement: repositories are scanned for ownership, missing ownership opens a 30-day archive warning issue, unresolved issues lead to archiving, and resolved issues

Chúng tôi đã lên lịch chạy CronJob lần đầu vào sáng thứ Bảy vì nghĩ rằng sẽ không ai để ý… Sai lầm lớn! Các vấn đề bắt đầu xuất hiện trong các kho lưu trữ trên toàn tổ chức, và mọi người bắt đầu đổ xô lên Slack, hỏi về vấn đề mới này trong kho lưu trữ của họ vì nó thông báo rằng kho sẽ bị lưu trữ. Tại một công ty phân tán toàn cầu, luôn có người trực tuyến.

Sau thời gian ân hạn 30 ngày, chúng tôi đã lưu trữ bất kỳ kho lưu trữ nào vẫn chưa được thiết lập quyền sở hữu. Chúng tôi chọn lưu trữ vì nó có thể đảo ngược và không phá hủy: kho lưu trữ trở thành chế độ chỉ đọc và GitHub Actions ngừng chạy, nhưng không có gì bị xóa. Nếu ai đó cần lại, chúng tôi cung cấp một cách dễ dàng để họ hủy lưu trữ, thiết lập quyền sở hữu và tiếp tục. Điều đó cho phép chúng tôi áp dụng việc lưu trữ một cách an toàn trên diện rộng thay vì tranh luận về từng trường hợp ngoại lệ.

Sau khi thời gian ân hạn ban đầu trôi qua và phần lớn việc lưu trữ đã hoàn tất, chúng tôi đã thắt chặt vòng lặp thực thi từ 30 ngày xuống còn một giờ. Một kho lưu trữ mới nếu bằng cách nào đó vượt qua yêu cầu sở hữu tại thời điểm tạo sẽ bị gắn cờ gần như ngay lập tức.

Những điểm khó khăn

Việc này hầu hết diễn ra suôn sẻ, với hai sự cố nội bộ nhỏ làm lộ ra một số trường hợp ngoại lệ thú vị.

Sự cố đầu tiên là do lưu trữ một kho lưu trữ chưa được áp dụng quyền sở hữu. Datadog đã được cấu hình để mở các vấn đề (issues) trong kho lưu trữ đó như một phần của quy trình giám sát. Khi kho lưu trữ bị lưu trữ và Datadog không thể tạo vấn đề, dịch vụ giám sát nội bộ của chúng tôi đã nhận thấy và tự động gửi thông báo (page) cho nhóm sở hữu, và họ đã leo thang vấn đề lên cho chúng tôi.

Sự cố đó đã làm lộ ra một khoảng trống trong cách chúng tôi thông báo. Các vấn đề về quyền sở hữu đã xuất hiện trong các kho lưu trữ, nhưng không ai được thông báo trực tiếp. Chúng tôi đã khắc phục điều này bằng cách @-mention các quản trị viên kho lưu trữ và gán tất cả người dùng có quyền ghi làm phương án dự phòng cho các vấn đề về quyền sở hữu. Bằng cách đó, các vấn đề không thể bị chôn vùi hoặc bỏ qua, và những người thực sự có thể thiết lập quyền sở hữu sẽ thấy chúng ngay lập tức.

Sự cố thứ hai là vấn đề về độ tin cậy của dữ liệu. Mặc dù chúng tôi đã có khả năng chống chịu với sự cố Service Catalog, nhưng chúng tôi đã không cân nhắc rằng nó có thể trả về dữ liệu cũ hoặc dữ liệu bị hỏng. Nếu dữ liệu xấu khiến ứng dụng nghĩ rằng một loạt kho lưu trữ đã mất mục Service Catalog trong khi thực tế không phải vậy, chúng tôi sẽ lưu trữ hàng loạt các kho lưu trữ có chủ sở hữu hoàn toàn hợp lệ.

Để giảm thiểu rủi ro lưu trữ các kho lưu trữ hợp pháp, chúng tôi đã thêm một ngưỡng tối thiểu (low water mark). Trong mỗi lần chạy, trước khi thực hiện bất kỳ hành động nào, ứng dụng sẽ kiểm đếm số lượng kho lưu trữ sắp được lưu trữ và số lượng vấn đề sắp được mở. Nếu con số vượt quá một ngưỡng thận trọng, nó sẽ hủy bỏ hoàn toàn và kích hoạt một cảnh báo Datadog thay vì mạo hiểm chạy một quy trình lỗi. Nếu Service Catalog không thể truy cập được, công việc sẽ bỏ qua xác thực Service Catalog và chỉ kiểm tra những gì nó có thể xác minh độc lập.

Kết quả qua các con số

Chúng tôi kết thúc với khoảng 3.000 kho lưu trữ đang hoạt động và 11.000 kho đã lưu trữ (tăng từ khoảng 3.000 kho đã lưu trữ lúc bắt đầu). Toàn bộ nỗ lực mất chưa đầy 45 ngày từ lần chạy đầu tiên (sáng thứ Bảy) đến trạng thái ổn định. Mọi kho lưu trữ đang hoạt động hiện đều có chủ sở hữu đã được xác thực, nếu không nó sẽ bị lưu trữ.

Nhiều kho lưu trữ mới được lưu trữ đó đã không có commit nào trong nhiều năm: các thử nghiệm bị bỏ hoang, các dự án hackathon đã hoàn thành và thậm chí cả các bản mẫu của một người từ năm 2008! Việc lưu trữ chúng cuối cùng đã giảm diện tích bề mặt của chúng tôi và làm cho danh mục kho lưu trữ đang hoạt động phản ánh đúng thực tế.

Duy trì quyền sở hữu

Đạt được độ bao phủ 100% chỉ hữu ích nếu nó duy trì ở mức 100%, vì vậy chúng tôi đã thực thi các thuộc tính sở hữu trên mọi quy trình tạo kho lưu trữ, bao gồm trang tạo kho lưu trữ (hiển thị bên dưới), các công cụ và tự động hóa nội bộ, khiến chúng trở thành bắt buộc đối với tất cả các kho lưu trữ mới.

GitHub repository creation page showing required ownership custom property fields.

Chúng tôi cũng thắt chặt vòng lặp thực thi: các kho lưu trữ mất quyền sở hữu hiện sẽ bị gắn cờ trong vòng một giờ thay vì thời gian ân hạn 30 ngày như ban đầu.

Mỗi loại hình sở hữu có các đặc điểm bền vững riêng và chúng tôi đã thiết kế dựa trên chúng. Các mục trong Service Catalog tuân theo vòng đời dịch vụ: khi một dịch vụ bị ngừng hỗ trợ, các kho lưu trữ của nó thường cũng bị lưu trữ, và đó là hành vi dự kiến. Các nhóm được xác thực là có ít nhất một thành viên, và sự tồn tại cũng như tư cách thành viên của nhóm thường khá ổn định. Các tài khoản Hubber cá nhân chỉ trở nên không hợp lệ khi ai đó rời công ty, điều này thường có nghĩa là các kho lưu trữ cá nhân của họ nên được lưu trữ bất kể thế nào. Đối với bất kỳ kho lưu trữ nào đủ quan trọng để tồn tại lâu hơn một cá nhân, quyền sở hữu nên là một nhóm hoặc một dịch vụ, không phải một cá nhân.

Điều này có ý nghĩa gì với bạn

Bạn có thể triển khai một mô hình sở hữu tương tự ngay hôm nay bằng cách sử dụng GitHub custom properties. Dưới đây là cách tiếp cận mà chúng tôi đề xuất:

GitHubQuản trị phần mềmQuy trình kỹ thuậtBảo mậtDevOps
Đọc bài gốc

Bài viết được AI dịch và tổng hợp tự động từ GitHub Blog. Liên kết bài gốc ở phía trên. AIHOT.vn luôn dẫn nguồn đầy đủ — nếu bạn thấy điểm cần chỉnh sửa, hãy gửi ý kiến tại trang phản hồi.