產物公開分享(公開 HTTPS 連結)
把 .md / .html / .xlsx 產物發佈為無需登入的短鏈,Slack/郵件只發連結不發文件;支援 TTL / 密碼 / 下載次數 / HTML 線上預覽。
如果你的工作流程產生了一份報表 (.md / .html / .xlsx / .pdf) 要發給別人看,最直接的辦法是讓 Slack/郵件模組上傳檔案附件。但大文件會慢,訊息平台通常有單文件大小和附件數量限制。
產物公開分享 是另一條路:把單個產物發布成一個無需登入的 HTTPS 短連結,訊息裡只發連結,點開就能看 —— 檔案本身留在伺服器,既省流量,又支援瀏覽器直接預覽(.md 可以線上渲染成 HTML)。一次要分享多個檔案時,還可以把整個產物目錄發布成一個連結,見下方「目錄級公開連結」。
什麼時候用
- 報表 / 儀表板要發 Slack / 飛書 / 郵件,不想讓所有人各存一份 3MB 的 xlsx
- 需要讓外部協作者 (沒有平臺賬號) 看一份 app store 數據快照
- 臨時分享一份 .md 結論給客戶,希望對方用手機瀏覽器直接看 HTML
- 要給鏈接一個過期時間 / 下載次數上限 / 密碼保護
怎麼用 —— 從 UI 生成
- 打開一條已經執行完的 execution,切到"產出物"Tab,看到每個產物旁邊有一個 🔗 分享 按鈕
- 點擊 🔗 分享,彈出分享對話框
- 按需設定:
- 存取範圍:公開(預設)/ 密碼存取 / 團隊內 / 指定成員,詳見下方「存取範圍與存取申請」
- 有效期:永不過期(預設)/ 1 小時 / 24 小時 / 7 天 / 30 天,會記住你上次的選擇
- 下載次數上限:0 = 不限制,>0 = 用完後鏈接自動失效
- 存取密碼(密碼存取模式):點開連結時瀏覽器彈出密碼框輸入
- 在線 HTML 渲染 (.md 專屬):勾選後訪問鏈接直接看到排版好的 HTML,不是下載 .md 源文件
- 點「產生連結」→ 得到形如 https://braidrun.com/p/a/hN2kQ9... 的 URL,點「複製」貼上到任意地方
怎麼用 —— 在工作流裡自動發佈(推薦)
工作流程執行完自動把產物變成公開連結,再自動把連結推到 Slack —— 全程無需手動點擊分享。
工作流程引擎會在每個 code step 自動注入本次執行 ID、短期存取權杖與平台存取位址。內建 artifact publish 模組會讀取這些運行期參數,所以你只需要告訴它"分享哪個步驟產生的產物"(from_step)。訪問令牌有效期較短,運行結束後無需手動維護。
典型三步編排
- 生成產物的步驟照常寫,不需要任何特殊標記 —— 例如:
- step: build_report agent: reporter input: | 生成今天的业务报表,写入 /tmp/.../daily.md。 # 这一步完成后,引擎自动注册一个产物(execution 的 artifacts 列表里会出现) - 接上內置 artifact publish 模塊,傳入上一步的步驟名 `from_step: build_report`。模塊會自動查 execution 的產物列表,找到那個步驟產生的文件,生成公開鏈接:
- step: share_report sub_workflow: name: dingyue-module-artifact-publish inputs: from_step: "build_report" # ← 唯一必需字段:引用上一步的步骤名 ttl_minutes: "0" # 永不过期;如需限时可改成分钟数 render_markdown_as_html: "true" # .md 直接在线 HTML 预览 # base_url / api_token 不用填 —— 引擎自动注入运行时访问令牌 outputs: share_url: public_url # 下游可以用 {{var:share_url}} 引用 depends_on: [build_report] - 再接一個內置 Slack 投遞模塊,把 public_url 傳進去 → Slack 只收到一條"文字消息+鏈接",不上傳文件:
- step: notify sub_workflow: name: dingyue-module-slack-deliver inputs: slack_webhook_url: "{{var:slack_webhook_url}}" message_text: "📊 今日报表已生成" public_url: "{{var:share_url}}" # ← 复用 share_report 的输出 depends_on: [share_report]
多產物怎麼辦
如果 build_report 步驟產生了多個文件(比如同時寫了 daily.md 和 metrics.json),用 artifact_name 過濾:
- step: share_report
sub_workflow:
name: dingyue-module-artifact-publish
inputs:
from_step: "build_report"
artifact_name: "daily.md" # ← 精确挑选
ttl_minutes: "0"
outputs:
share_url: public_url不加 artifact_name 時模塊取第一個匹配的產物,並在日誌裡提示還有幾個未使用的。
目錄級公開連結:一個 URL 分享整個產物目錄
單檔案連結一次只能分享一個產物。如果一次執行產出了一組檔案(報表 + 資料 + 圖片,甚至一個完整的多頁靜態網站),可以把整個產物目錄發布成一個連結:
- UI 入口:執行詳情的「產物」Tab 點「分享全部產物」,產生涵蓋這次執行全部產物的目錄連結;設定項(存取範圍 / 有效期 / 下載配額 / 密碼 / 線上渲染)與單檔案一致,另可自訂顯示名稱
- API 還支援只分享某個步驟的產物。分享整個執行:
POST /api/executions/{id}/directory-public-link;只分享單一步驟:POST /api/executions/{id}/steps/{stepName}/directory-public-link - 連結形如 https://braidrun.com/p/d/hN2kQ9.../,存取者無需帳號(公開模式下)
存取者看到什麼
- 預設是一個檔案列表頁:檔名、大小、類型,以及連結的有效期與下載配額
- 目錄根部有 index.html 時,直接按靜態站點開啟 —— 工作流產生的多頁 HTML 報告可以整站分享;URL 加 ?listing=1 強制回到檔案列表檢視
- 勾選了線上渲染時,目錄裡的 .md 檔案以排版好的 HTML 展示
- 目錄內檔案始終由平台按正確的 Content-Type 轉發(不走物件儲存 302 直連),保證 HTML / CSS / JS 能被瀏覽器正常渲染
- 下載配額按整個目錄累計,用完後連結自動失效
存取範圍與存取申請
單檔案連結與目錄連結共用同一套存取範圍:
| 模式 | 誰能開啟 |
|---|---|
PUBLIC 公開 | 任何拿到連結的人 |
PASSWORD 密碼訪問 | 拿到連結且知道密碼的人;瀏覽器彈窗輸入,指令碼用戶端用 Authorization: Basic 或 X-Artifact-Password 標頭 |
TEAM 團隊內 | 需登入 Braidrun 帳號,且屬於指定團隊 |
USERS 指定成員 | 需登入,且在成員名單裡;名單只能從所選團隊的成員裡挑 |
團隊內 / 指定成員模式下,連結變成「需要登入的深層連結」:未登入存取會被引導去登入;登入了但不在名單裡,會看到「無權存取」頁。
存取申請流程(團隊內 / 指定成員模式可選啟用):
- 建立連結時勾選「允許登入使用者在無權存取時提交申請」
- 無權存取者開啟連結,在「無權存取」頁填一份申請表單,可附說明;重複提交會更新原申請
- 分享者或連結管理員在「帳戶 → 分享管理」裡批准 / 拒絕;批准前需要確認對方已屬於所選團隊
- 批准後對方即被加入可存取名單,用原連結直接開啟
管理目錄連結
- 「帳戶 → 分享管理」把單檔案與目錄連結放在一起管:改存取範圍、改有效期、撤銷,以及查看存取計數與存取日誌(時間、帳號身分、IP、User-Agent)
- 對應的管理 API,列出 / 修改 / 撤銷分別是:
GET /api/directory-public-links·PATCH /api/directory-public-links/{token}·DELETE /api/directory-public-links/{token} - 建立者預設是連結管理員,可以再指定額外管理員,一起處理存取申請與撤銷
支持的分享方式
| 部署 | 是否支持 | 說明 |
|---|---|---|
| 單機 + 本地盤 | ✅ | 平台直接返回文件內容 |
| 多節點 + 本地盤 | ⚠️ 不推薦 | 請求可能命中沒有檔案的節點 → 410 Gone。建議啟用物件儲存。 |
| 任意節點數 + 物件存儲 | ✅ 推薦 | 302 到臨時簽章下載連結 (10 分鐘 TTL,每次造訪新簽),平台不轉送檔案流量 |
上表針對單檔案連結;目錄連結始終由平台轉發檔案流,任何部署形態都可用。
安全與合規
- Token 不可枚舉 —— 24 字節 SecureRandom → base62 ≈ 143 bits 熵,暴力掃描不可行
- 防爬蟲索引 —— 響應頭 X-Robots-Tag: noindex, nofollow + Referrer-Policy: no-referrer,Google/Bing 不會索引鏈接
- 速率限制 —— 閘道層: 同一 IP 每秒 10 次,突發 20 次;服務層: 按 token 的 maxDownloads 硬性限制
- 密碼保護 (可選) —— Argon2id 雜湊;瀏覽器存取時彈窗輸入,指令碼用戶端用 Authorization: Basic 或 X-Artifact-Password 標頭。密碼不放 URL 查詢參數,避免落入存取日誌
- 審計日誌 —— 每次創建 / 訪問 / 撤銷都寫一條 audit_log,包含客戶端 IP + User-Agent + 時間戳
- GDPR 兼容 —— 賬戶刪除時自動級聯清理所有鏈接;數據導出時 artifact_public_links.jsonl 打入 ZIP
- 即時撤銷 —— 分享管理頁面點"撤銷"即刻生效,被撤銷的鏈接訪問直接 410 Gone (不是 404,避免和"不存在"混淆)
管理已分享的鏈接
進入"賬戶 → 分享管理"(或直接訪問 GET /api/public-links) 可以看到你創建過的所有鏈接、訪問計數、是否已撤銷。點撤銷按鈕鏈接立刻失效。
常見問題
Q: 鏈接點開為什麼顯示 410 Gone?
- 鏈接已過期(有效期到了)
- 鏈接已被創建者或管理員撤銷
- 下載次數已達上限(配額消耗完會自動失效)
- 密碼輸錯了(沒輸過密碼時會先看到瀏覽器的密碼彈窗,而不是 410)
Q: 我能讓鏈接永不過期嗎?
可以,但 UI 會彈一個二次確認 —— 永久鏈接意味著除非你手動撤銷,任何拿到鏈接的人都可以永久訪問,請謹慎。管理員可以通過 BRAIDRUN_PUBLIC_LINK_REJECT_PERMANENT=true 全局禁用永久鏈接。
Q: 鏈接會被搜索引擎索引嗎?
不會。響應頭強制 noindex,nofollow,並且 nginx 層 also 追加一道。但如果你把鏈接貼到公開網頁上,搜索引擎可能通過外部爬蟲發現 URL —— 所以永遠不要把鏈接公開到 GitHub README / 博客文章裡。
Q: 多大的文件合適?
物件儲存模式下:理論上無限;實際上受限於使用者的瀏覽器逾時 (一般幾十 MB 沒問題)。本機碟模式下:受限於平台檔案讀取速度,不建議超過 100MB。
Q: 如果我刪除了產物對應的 execution,舊鏈接還能用嗎?
不能。刪除 execution 的時候系統會級聯撤銷所有指向該 execution 的鏈接,後續訪問直接 410 Gone。
Q: 這個功能是默認開啟的嗎?
需要管理員通過環境變量 BRAIDRUN_PUBLIC_BASE_URL 顯式啟用;未啟用時 UI 看不到分享按鈕。見運維文檔 PRODUCTION_GUIDE §2.4。