合併 GitHub Actions 的 IP address

GitHub 官方文件「About GitHub's IP addresses」中,是有提到 https://api.github.com/meta 這組 API endpoint,可以取得當下的 GitHub Actions 所使用的連外 IP address,不過如果你實際掃下來後會發現量相當大,以現在的情況來說,IPv4 address 有 3708 筆,IPv6 address 則有 801 筆:

$ cat github-actions-ipv4.txt | wc
   3708    3708   58233
$ cat github-actions-ipv6.txt | wc
    801     801   17522

實際去看的時候會看到一些吐血的,像是這包 /31 的:

13.105.49.0/31
13.105.49.2/31
13.105.49.4/31
13.105.49.6/31
13.105.49.8/31
13.105.49.10/31
13.105.49.12/31
13.105.49.14/31
13.105.49.16/31

這包還真的就整整 128 筆,你就不能輸出個 13.105.49.0/24 嗎...

ChatGPT 問了要怎麼解決,被提示有 netmask 這個工具可以用,不需要另外自己編譯,可以直接用 apt 裝起來然後倒進去讓他跑就好,整包搭配 jqHTTPie 處理掉 (換 curl 基本上也沒問題):

netmask --cidr -- $(http https://api.github.com/meta | jq -r '.actions[]')

Update:看到資安的朋友按讚突然想到,這邊用了 $() 把資料丟到 command line 包裝,可能會有安全上的顧慮,請自己斟酌...

不過整包 (IPv4 + IPv6) 還是有 3187 行,但總是有個方法可以整理起來用,不用自己刻一堆程式處理...

GitHub 的 Monaspace 修正了 Terminal 上選不到的問題

去年 GitHub 發表 Monaspace 後,我測了一下就遇到這個問題就丟在旁邊:「Can't see monaspace on terminal」,早上看到修正完票關起來了。

Monaspace 比較特別的是直接提供五種不同的樣式可以選擇:

剛剛測了其中幾個,其中 Xenon 搭個明體類的還蠻適合的 (像是 Noto Serif CJK TC)...

OpenSSL 決定把 release site 改到 GitHub 上

OpenSSL 宣佈了之後會以 GitHub 為主要發佈平台:「Releases Distribution Changes」。

舊的 ftp & rsync 以及 git protocol (9418/tcp 的協定) 都打算淘汰掉:

We’re no longer using our old ftp, rsync, and git links for distributing OpenSSL. These were great in their day, but it’s time to move on to something better and safer.

其中 FTP 與 rsync 都已經停掉了,接下來是今年六月要停掉 ftp.openssl.org 的 HTTPS 介面以及 git.openssl.org 的 git protocol:

ftp://ftp.openssl.org and rsync://rsync.openssl.org are not available anymore. As of June 1, 2024, we’re also going to shut down https://ftp.openssl.org and git://git.openssl.org/openssl.git mirrors.

然後主力轉戰到 GitHub 上面:

GitHub is becoming the main distributor of the OpenSSL releases.

算是省事的作法,畢竟自己弄 infrastructure 不算太輕鬆

另外 OpenSSL 畢竟是個歷史頗久的軟體了,有「遵循古法」所以 release 都會有 PGP/GPG sign,這部分如果還是獨立於 GitHub 平台的話就沒什麼問題,代表還是有非 HTTPS 的 integrity 方法可以確認檔案沒被抽換過。

(但如果綁進 CI/CD 流程的話就廢了?)

查詢 GitHub 上面 repository 的公開記錄

起因應該是「Claim: Private GitHub repos included in AI dataset (lurk.org)」這邊的討論,原文是 @emenel@post.lurk.orghttps://post.lurk.org/@emenel/112111014479288871 這邊宣稱他在 GitHub 的 private repository 被當作 training data 蒐集走使用。

而 GitHub 有公開全站的 public event data,所以 Simon Willison 就拿這份資料直接組了一個工具出來用:「GitHub Public repo history」。

這樣可以直接 auditing 對應的說法,不過看了一下 GitHub 上的帳號 emenel (上面連結是到同一個站,應該是同一個人),目前看起來已經把所有 repository 都刪掉了...

展開所有 GitHub comment 的 Bookmarklet

看到 Eric Meyer 弄了一個可以展開 GitHub comment 的 bookmarklet:「Bookmarklet: Load All GitHub Comments」。

分析他的程式碼,稍微手動排一下,可以看出來邏輯蠻簡單的,就是去找出對應的 button,然後模擬按下去的 event:

javascript:function start() {
  let buttons = document.querySelectorAll('button');
  let loaders = [];
  for (let i = 0; i < buttons.length; i += 1) {
    if (buttons[i].textContent.trim() == 'Load more%E2%80%A6') {
      loaders.push(buttons[i]);
      buttons[i].dispatchEvent(new MouseEvent('click', {
        view: window,
        bubbles: false
      }))
    }
  }
  if (loaders.length > 0) {
    setTimeout(start, 5000)
  }
}
setTimeout(start, 500);
void(20240130);

意外可以看到一些應該是作者以前寫習慣的寫法 (畢竟 Eric Meyer 這個名字二十年前就聽過了?),現在 for 拿來當 iteration 應該會用 of 的語法了,另外是 letconst 的差異...

還好這邊還是用 querySelectorAll(),而不是直接看到 getElementsByTagName(),不然就更有考古感了...

拿「Quadratic time internal base conversions #90716」這個測了一下還行,不過我不是那麼常用到,大概不會掛到 bookmark bar 上面...

作者有提到考慮過寫成 userscript,不過看起來是懶 XD

GitHub 新版 Code Search 後面砍掉重練的過程

Hacker News 上看到「Lessons from building GitHub code search (youtube.com)」這篇在講 GitHub 的 Code Search (今年九月在 Strange Loop 上的演講),同時演講者 Luke Francl (帳號是 100k) 也有在 Hacker News 上留言回答一些問題:

影片裡面有不少資訊,挑我自己覺得有趣的地方整理一下。(不是依照影片的順序)

首先是現成的 search engine (Elasticsearch) 會濾掉太多資訊,其中一種例子就是在程式語言中,各種 token 像是 <= 以及 > 這些,都算是有用的資訊。

另外一方面是 Elasticsearch 的架構下沒有辦法利用 fork 的性質 (以及 Git 的 branch 性質),所以在處理 fork 類的 repository 會造成大量重複的資料,但 fork 的資料會有 99% 以上是與原來的 repository 相同。

舊的系統有 312 servers,包括了 24960 cores 與 20TB RAM,直接平均下來,每一台機器是 80 cores 與 65GB RAM,而跑一次 reindex 會需要幾個月的時間。

新的系統則降到了 130 servers,包括了 8320 cores,但記憶體加到了 65TB RAM,直接平均下來,每一台機器是 64 cores 與 512GB RAM,後面有列出來是 Azure 的 L64s v3,剛好就是 64 cores 與 512GB RAM,然後帶有 640GB temp disk 與 8*1.92TB 的 NVMe disk。

另外有提到這套新的系統雖然比較小 (除了記憶體),但卻是 3 clusters,這也剛好解釋記憶體變成原來三倍的原因。

而更重要的是,因為有多個系統,所以他們可以在上面對 production 等級資料量進行測試,而且不用害怕炸掉東西。

而且新的系統從零 rebuild 一次只需要幾天,不像之前需要好幾個月。這些改變使得 engineer 更容易進行個重嘗試與改善,而不用把精神花在要怎麼維持相容性。

回到 CPU 數量的下降,這邊沒有直接提到原因,但演講裡有提到有不少東西改用 Rust 寫,等於是從 JVM 換到原生程式碼,對於會有大量時間花在 CPU 運算的服務來說是個明顯的加分。

中間有兩個提到演算法的事情也蠻有趣的。

第一個是在 Delta compression 的地方,把 fork 後的差異當作是 delta,要最小化整個 fork tree 的成本,剛好把這個東西轉換成圖論的問題,就可以套用 Minimum spanning tree 這個經典的演算法,而且 MST 太經典,有很多變形也都有人研究過,有限成的演算法可以用。

另外一個提到的是 Alexander Neubeck,從 LinkedIn 上的資料可以看到他在 Google 的時候就是負責 Code Search,後來到 GitHub 看起來剛好加入對應的團隊,他開發了一個新的資料結構 Geometrics XOR filter 來解決 Delta compression 遇到的問題。

在 Hacekr News 上的討論可以看到有人抱怨還是缺了重要的功能,不過這畢竟是砍掉重練開始搞,而且是配合 Git 與 GitHub 的特性設計的,可以預期會缺東西,但就像演講裡提到的,新的架構可以讓整個團隊更快的迭代進行各種嘗試,後續就比較會是官方要取捨實作哪些功能了...

GitHub 的 MySQL 5.7 升級到 8.0 的細節

GitHub Blog 上面寫了一篇關於 GitHub 怎麼把 MySQL 5.7 升級到 8.0 的過程,有點長度但是裡面有蠻多數字與架構可以看:「Upgrading GitHub.com to MySQL 8.0」。

開頭先順便提一下,看這篇後可以交叉看 GitHub 的 Incident History,有幾次跟 database 有關的事件,雖然不能直接確認與這波升級有關,但心裡可以有個底...

數字與時間的部分主要是這些:

Our fleet consists of 1200+ hosts. It’s a combination of Azure Virtual Machines and bare metal hosts in our data center.

We store 300+ TB of data and serve 5.5 million queries per second across 50+ database clusters.

Preparation for the upgrade started in July 2022 and we had several milestones to reach even before upgrading a single production database.

另外雖然沒有明講,但從文章中其他段落的描述,以及相關的圖片,可以看出來 GitHub 是使用 single-primary (single-master) 的架構,這邊沒有用到 multi-primary (multi-master) 類的架構:

We opted not to do direct upgrades on the primary database host. Instead, we would promote a MySQL 8.0 replica to primary through a graceful failover performed with Orchestrator.

後續升級的部分有點長,第一波關於 read-only replica 的部分雖然有些地方沒講清楚,但基本上大家的作法都大同小異:

比較明顯有疑問的是,第一步為什麼不是直接生一台新的 8.0 觀察 (這樣觀察到的環境才會與後續過程接近),而是 in-place upgrade,而後續開的機器又是 provision。不過這個算是小問題...

比較值得研究的是在第二步與第三步的說明裡面提到的 primary (master) 這塊。

第二步是先改變 topology,這個架構算是蠻特別的的過渡架構,只會維持幾個小時;會把其中一台 8.0 replica 拉起來放在中間,然後再串一台 5.7 replica,接下去再串 5.7/8.0 的 read-only replicas:

第三步把 primary (master) 指到 8.0 上:

這個特別的架構可以推敲出來是想要能夠快速在有狀況時完全 rollback 回 5.7,不過可以馬上想到 8.0 的資料丟到 5.7 上的問題。

MySQL 的慣例是下一個版本的 replication 通常都會通 (像是 5.0 -> 5.1,或是 5.1 -> 5.5,而這邊的例子是 5.7 -> 8.0),這在官方的文件「Replication Compatibility Between MySQL Versions」有提過。

但反過來就不一定了,這也是看到圖時馬上會想到的問題,在文章裡面也有提到:

MySQL supports replication from one release to the next higher release but does not explicitly support the reverse (MySQL Replication compatibility).

所以他們只能在 staging 上演練看看,找出會炸掉的東西,然後得提前先修改完:

When we tested promoting an 8.0 host to primary on our staging cluster, we saw replication break on all 5.7 replicas.

另外一方面,在文章開頭的地方也有提到利用 CI 事先找出問題:

We added MySQL 8.0 to Continuous Integration (CI) for all applications using MySQL. We ran MySQL 5.7 and 8.0 side-by-side in CI to ensure that there wouldn’t be regressions during the prolonged upgrade process. We detected a variety of bugs and incompatibilities in CI, helping us remove any unsupported configurations or features and escape any new reserved keywords.

用這些方法儘量把問題圍堵找出來,而真的遇到在 production 上的問題時,應該是看情況來決定要不要 rollback 回 5.7 整包重來?

就... 看看當作一個有趣的 case study。

測試 GitHub 與 AWS 可以多快偵測出外洩的 token

前幾天在 Hacker News 上看到「What happens when you leak AWS credentials and how AWS minimizes the damage (xebia.com)」這篇,原文連結在「What happens when you leak AWS credentials and how AWS minimizes the damage」這邊。原文跟 Hacker News 上的寫到東西都頗有趣的,可以分開來講。

先是原文的部份,他抓了一些時間軸:

12:33:12 – Pushed the credentials to GitHub
12:34:19 – The AWSCompromisedKeyQuarantineV2 policy is attached to the IAM user test-user by AWS
12:34:32 – Various List and Describe calls are made using the leaked credentials
12:35:08 – Received an email from AWS with the subject ‘ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account 12345678’

可以看到推上 GitHub 後,AWS 在一分七秒後就自動加上 AWSCompromisedKeyQuarantineV2 以減少災害擴大,然後再發信件通知。

這個功能可以參考 GitHub 的文件說明:「About secret scanning - GitHub Docs」。

另外在 Hacker News 上面看到有人直接把 secret scanning 當作 API 串來用 (噗),把在 PyPI 上面掃到的 AWS secret 丟上 GitHub 觸發後續的機制:

I set up a project[1] to automatically leak AWS secrets published to the Python package index, which then triggers the secret scanning process and quarantines the keys[2]

1. https://github.com/pypi-data/pypi-aws-secrets

2. https://github.com/pypi-data/pypi-aws-secrets/blob/main/keys...

Gitea 推出 Actions

Hacker News 上看到 Gitea 出 1.19 的消息:「Gitea 1.19 (gitea.io)」,在討論裡面就有人提到 Gitea Actions,從名字就知道是抄自 GitHub Actions,算是 Gitea 開始建立自己的 DevOps 生態系的一個重要功能。

目前這個功能還被掛在 EXPERIMENTAL 上,預設是關閉的,而且我自己試了一下也的確試跑不太起來,出現這樣的錯誤訊息,暫時也沒空去細追:

time="2023-03-28T17:36:37Z" level=info msg="poller: request stage from remote server" func=pollTask
time="2023-03-28T17:36:37Z" level=error msg="cannot accept task" error="unknown: rpc error: code = Internal desc = pick task: CreateTaskForRunner: Error 1366 (HY000): Incorrect string value: '\\xF0\\x9F\\x8E\\x89 T...' for column 'name' at row 1" func=pollTask
time="2023-03-28T17:36:37Z" level=error msg="can't find the task: unknown: rpc error: code = Internal desc = pick task: CreateTaskForRunner: Error 1366 (HY000): Incorrect string value: '\\xF0\\x9F\\x8E\\x89 T...' for column 'name' at row 1" func=Poll

接下來會有更多人跳進去試,之後再來看看成熟度如何...

GitHub 更換 github.com 的 SSH host key (RSA 部份)

看到 GitHub 宣佈更換 SSH key (RSA 的部份):「We updated our RSA SSH host key」。

Hacker News 上的「We updated our RSA SSH host key (github.blog)」這邊有人提到官方文件 (原文裡面也有提到),裡面會列出對應的 key:「GitHub's SSH key fingerprints」。

只是看起來這些大公司依然對 DNSSEC + SSHFP 這樣的組合沒興趣...