Add post: How I Vet an Open-Source Dependency Before Betting On It (EN + ZH)
Deploy / build (push) Successful in 15s

New `devops` post on vetting an upstream dependency before building on it:
the six checks that corrected six assumptions from a 1,306-line architecture
spec — repo vital signs via the GitHub API, grepping for the feature instead
of reading for it (OIDC/SSO/SAML → 0 hits), reading a feature doc's target
branch (white-label lives on `multi-tenant`, not `main`), reading the data
model rather than the feature list (percent/fixed vs five assumed rule types),
the Community-vs-Enterprise tier gate (API tokens free, SSO paid), and whether
the money rail works in-country (selfhost + manual payouts, not Stripe Connect).
Closes with the fallback question and the authentik proxy-provider answer.

- EN: src/content/posts/vetting-an-open-source-dependency-before-you-bet-on-it.md
- ZH: src/content/posts/zh/<same slug>.md (same filename → auto language switch)
- Custom OG (1200x630) + banner (1600x900) art via TERMINALS/BANNERS entries
- pubDate 2026-09-29; build verified 93 pages, 17/17 content checks, listing
  order monotonic on /posts/, / and /zh/

Note: the generator maps also carry two entries belonging to parallel
in-flight posts (adding-english-mode…, and the sessions' other slugs);
their post files were left uncommitted.
This commit is contained in:
2026-09-29 01:07:43 +08:00
parent a77fb0b5d3
commit 87111360ce
6 changed files with 370 additions and 0 deletions
@@ -0,0 +1,113 @@
---
title: "如何在押注前验证一个开源依赖:我用的六项检查"
description: "六项检查,专门抓出「文档说得漂亮、代码里其实没有」的仓库:用 grep 找功能、读文档头部标注的目标分支、看清付费档位门槛,以及收款通道在不在你的国家能用。"
pubDate: 2026-09-29
category: devops
tags: ["open-source", "due-diligence", "oidc", "self-hosting", "docker"]
ogImage: "/og/vetting-an-open-source-dependency-before-you-bet-on-it.png"
banner: "/banners/vetting-an-open-source-dependency-before-you-bet-on-it.png"
draft: false
---
有人给我一份 1306 行的伙伴系统架构规格书。读起来像一份计划:前后一致、交叉引用、语气笃定。它指定一个自托管的开源引擎作为归因与佣金层,并且假定了那个引擎的三件事——它支持 OIDC,所以我现有的身份提供方能登录伙伴;它的佣金规则覆盖业务需要的五种形态;它的白标功能已经上线。
十分钟的 `curl` 加 `grep` 之后,三件里有两件是假的,第三件只对了一半。
这没什么稀奇。README 描述的是**产品**,仓库描述的是**软件**。这两者之间的落差,正是集成项目死掉的地方——而且在写任何代码之前,测量这个落差很便宜。
## 问题,写成我真的会去搜的那句话
**我怎么知道一个开源项目真的做了它文档宣称的事,然后才在它上面开始建东西?**
规格书是**关于别的软件**的一种主张。规格书越漂亮,它的假设就越像事实——这一份引用了来源、定义了稳定 ID、还画了一张「真源矩阵」。它唯一没做的事,就是核对链条下游那个引擎到底有没有实现被指派给它的功能。所以在安装任何东西之前,我去找那几个具体功能。
## 我一开始试的,以及为什么不够
**一、把 README 从头读到尾。** 它把流水线卖得很好:`click → identity → event → attribution → commission → payout`。但它一次都没说这个应用讲哪种认证协议。对一个你**必须要有**的功能来说,沉默不是中立——只是当页面其他部分都很有说服力时,一个「没被提到」很容易被眼睛滑过去。
**二、上网搜。** 好几条查询都没返回能用的结果。这个项目才几个月大,SEO 面很薄。对软件来说这没关系——源码**就是**文档。只是意味着阅读必须在仓库里进行,而不是在博客文章里。
**三、看到一份 78 KB 的功能设计文档,就假定功能已上线。** 它标着「FINAL, post-review」,列了三位评审,还带着日期。我把它当成了证据。这是三个推断里最糟的一个,也是最容易核对的一个。
## 真正定案的六项检查
### 1. 先看仓库的生命体征,再看任何功能宣称
```bash
curl -s -H "User-Agent: hermes" https://api.github.com/repos/<owner>/<repo> \
| grep -E '"created_at"|"pushed_at"|"stargazers_count"|"forks_count"|"open_issues_count"|"archived"|"spdx_id"'
```
返回的是:MIT、创建于 2026-04-23、最后推送 2026-09-10、8 个 star、3 个 fork、15 个 open issue、未归档。翻译过来就是:**真实、还在动、但非常小**——单一厂商,而且它同时卖托管档。现在我在开始评它的功能之前,先知道了我愿意把多少生意压在它身上。
### 2. 用 grep 去找功能,而不是用读的
```bash
grep -in 'oidc\|sso\|saml' README.md ARCHITECTURE.md docs/*.md | wc -l
```
零命中。这个应用用的是它自己的 magic-link 会话和按身份签发的 API key;它根本不讲 OIDC。就这一行输出,砍掉了计划里的一个阶段——「把门户挂到我们 SSO 后面」——否则这一步会在几周后才浮现,而且是在集成到一半、伙伴已经被邀请进来的时候。**用读的方式去找一个找不到的功能,就是你失去一个下午的方式;grep 让「不存在」这件事变得响亮。**
### 3. 读功能文档最上方那行「目标分支」
```bash
head -5 docs/white-label-custom-domains.md
```
`Target branch: multi-tenant`。这份文档描述的是**另一个分支**上的设计,不是你默认会安装的那个分支——它写的是在途工作,所以功能不在你会装下来的代码里。一份有评审、有日期、看起来已经完成的设计文档,完全可能描述着尚未上线的东西。这不是不诚实,设计文档本来就是这个样子。
### 4. 读数据模型,不要读功能清单
佣金那一节只列了两种规则类型——`percent`(带续期标记)与 `fixed`。业务规格书列了五种。这个落差不是 bug,而是我必须在**配置层**做的建模工作,不能指望产品自带:
| 规格书假设 | 引擎实际有的 |
|---|---|
| 首单奖励 | 对首个事件用一条 `fixed` 规则 |
| 按事件区分(`lead` vs `invoice_paid`) | 一个 campaign 一条规则——所以:两个 campaign |
| 续期佣金 | `percent` + `recurring: true` |
| 百分比 | `percent` ✅ |
| 固定金额 | `fixed` ✅ |
两种规则原语,五种行为——能做,但前提是你**一开始**就照这个设计,而不是在实现途中才发现。
### 5. 看清你需要的那项功能被锁在哪一档
同一个技术栈里还有个数据库工具,它的版本对照表很直白:
| 我需要的功能 | Community(免费) | Enterprise(付费) |
|---|---|---|
| API token,好让我自动化 | ✅ | ✅ |
| SSO / OIDC | ❌ | ✅ |
| 页面设计器、隐藏品牌、双因素 | ❌ | ✅ |
我想给「伙伴看到的那个门」用的东西(SSO)在商业门后面;而我想用来做自动化的东西(API token)是免费的。在围绕它做设计**之前**,先弄清每项需求落在墙的哪一侧。
### 6. 核对收款通道在你的国家能不能用
它的打款模型是 `stripe_connect | manual`,而自托管模式被写成「operator manages out-of-band」——也就是钱由你自己搬。Stripe Connect 不是马来西亚企业付钱给伙伴的方式,所以就是这一行决定了整个部署形态:自托管模式、手工打款、事件由我自己的订单系统推送过去,而不是依赖它内置的支付集成。这一行从来不会出现在营销页上,而它比任何功能都重要。
### 然后:在你需要之前,先问「兜底方案」
「如果我需要的功能不在,怎么办?」针对缺失的 SSO,答案是:不要把登录做进应用里,把登录放到应用**前面**。authentik 的 proxy provider 存在的意义就是保护「不支持 OIDC、SAML 或 LDAP 等原生认证协议的应用」,并且向上游注入 `X-authentik-username` 和 `X-authentik-groups` 头,于是反向代理就能承担准入判断。这就把「不支持 SSO」从一条否决理由,变成了一个下午的配置工作。
## 如果重来,我会怎么做
- **先写需求清单,再去找它。** 五行——**我**需要的功能——然后就搜这几个。从 README 的功能列表出发,等于用厂商的考卷给软件打分。
- **把「文档存在」和「功能上线」当成两件不同的事。** 去读那行目标分支。
- **用 grep,不要用读的。** 证明「有」很便宜;你要猎的是「没有」。
- **在决定之前先定兜底**,这样一个缺失的功能就只是一次设计调整,而不是一场意外。
- **把 commit 钉住。** 这个项目的 README 自己写着 API「stable but unversioned」,而且仓库里没有任何 OpenAPI 描述。没有可以编译期对齐的契约,那么 commit hash **就是**契约——我用到的端点要记进我自己的文档,升级前跑一遍回归。
## 结果
六个假设在大概十分钟的 `curl` 和 `grep` 里被修正,而当时一行集成代码都还没写。项目依然可行——只是换了形状:没有 OIDC、手工打款、钉住 commit,以及一份不再依赖某个未合并分支上功能的计划。
那份规格书乐观并没有错。它错在**没被验证过**——而这是整个项目里最便宜的修补项。
---
**你正在自托管技术栈上建东西,想在集成之前找人看一眼那些功能到底在不在?** 这正是我在做的复核工作。
[WhatsApp +60 12-797 2969](https://wa.me/60127972969) ·
[[email protected]](mailto:[email protected]?subject=Open-source%20dependency%20review) ·
[hoelee.com](https://hoelee.com)