-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 飞书多维表格投影——同步器+演练面+统一账本第 6 源(IR-0006 W3-F1 / ADR-0103 决策 7) #447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,82 @@ | ||||||||||||||||||||||||||||||||
| name: feishu-drill | ||||||||||||||||||||||||||||||||
| # 飞书投影演练面(宪法 §12 第四投影 / IR-0006 W3-F1 / 卡 #416 / ADR-0103 决策 7) | ||||||||||||||||||||||||||||||||
| # 手动 dispatch 驱动(无 cron——15min 日常节奏归 butler-ledger.yml 守卫调用, | ||||||||||||||||||||||||||||||||
| # 本面只做演练与复盘:sync 常规收敛 / verify 只读对账(不收敛=红,INV-05 演练)/ | ||||||||||||||||||||||||||||||||
| # rebuild 整表删除单轮重建(BEH-06 演练语义)。影子事件 relink 持久化到 | ||||||||||||||||||||||||||||||||
| # feishu-ledger 分支=evidence-query 第 6 源(append-only 台账,双侧验链防覆盖 | ||||||||||||||||||||||||||||||||
| # 掩盖篡改,同 butler-ledger 哲学);BUTLER_CARD 绑 #416——演练可追溯锚点。 | ||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||||
| mode: | ||||||||||||||||||||||||||||||||
| description: "演练模式:sync=常规同步 | verify=只读对账(漂移=红) | rebuild=删表重建" | ||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||
| default: "sync" | ||||||||||||||||||||||||||||||||
| type: choice | ||||||||||||||||||||||||||||||||
| options: [sync, verify, rebuild] | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| permissions: {} | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| concurrency: | ||||||||||||||||||||||||||||||||
| group: feishu-drill # 串行化:feishu-ledger append-only 不容忍并发追加 | ||||||||||||||||||||||||||||||||
| cancel-in-progress: false | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||
| drill: | ||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||
| timeout-minutes: 15 | ||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||
| contents: read # 读 governance/ 脚本 | ||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||
| persist-credentials: false | ||||||||||||||||||||||||||||||||
| - name: 投影演练(mode→feishu-sync 参数映射;verify 漂移=红) | ||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||
| GH_TOKEN: ${{ secrets.GOVERNANCE_TOKEN }} # label 真源读(缺=exit 2 fail-closed) | ||||||||||||||||||||||||||||||||
| FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }} | ||||||||||||||||||||||||||||||||
| FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }} | ||||||||||||||||||||||||||||||||
| FEISHU_BITABLE_APP_TOKEN: ${{ secrets.FEISHU_BITABLE_APP_TOKEN }} | ||||||||||||||||||||||||||||||||
| BUTLER_TRIGGER: drill | ||||||||||||||||||||||||||||||||
| BUTLER_CARD: Cloudbird-Software/.github#416 | ||||||||||||||||||||||||||||||||
| BUTLER_TENANT: cloudbird-internal | ||||||||||||||||||||||||||||||||
| MODE: ${{ inputs.mode }} | ||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 必须在同步步骤启用影子事件输出。
建议修改 BUTLER_CARD: Cloudbird-Software/.github#416
BUTLER_TENANT: cloudbird-internal
+ BUTLER_SHADOW_PAYLOAD: governance/feishu/shadow-evidence.jsonl
MODE: ${{ inputs.mode }}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||
| ARGS=() | ||||||||||||||||||||||||||||||||
| case "$MODE" in | ||||||||||||||||||||||||||||||||
| sync) ARGS=() ;; # 常规收敛(默认路径=日常 15min 同语义) | ||||||||||||||||||||||||||||||||
| verify) ARGS=(--verify) ;; # 只读对账:未收敛 exit 3=红(fail-closed) | ||||||||||||||||||||||||||||||||
| rebuild) ARGS=(--drop) ;; # 删表+单轮重建(BEH-06 演练) | ||||||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||||||
| python3 governance/feishu-sync.py "${ARGS[@]}" | ||||||||||||||||||||||||||||||||
| - name: 影子账本落盘(feishu-ledger 分支,IR-0006 W3-F1 / BEH-03) | ||||||||||||||||||||||||||||||||
| # feishu 源影子持久化:本地 shadow-evidence.jsonl relink 续接 feishu-ledger | ||||||||||||||||||||||||||||||||
| # 基链(双侧验链,防覆盖掩盖篡改)后写回。always():verify 红(exit 3)时 | ||||||||||||||||||||||||||||||||
| # 审计事件同样必须落账(append-only 纪律优先于本轮结论)。 | ||||||||||||||||||||||||||||||||
| if: ${{ always() }} | ||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||
| DRILL_TOKEN: ${{ secrets.GOVERNANCE_TOKEN }} | ||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||
| SHADOW="governance/feishu/shadow-evidence.jsonl" | ||||||||||||||||||||||||||||||||
| if [[ ! -s "$SHADOW" ]]; then | ||||||||||||||||||||||||||||||||
| echo "OK 本轮无影子记录(audit_emit 未触发或 skipped)——跳过(幂等)" | ||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||
| git config --global user.name feishu-drill-bot && git config --global user.email feishu-bot@users.noreply.github.com | ||||||||||||||||||||||||||||||||
| if ! git clone --depth 1 "https://x-access-token:${DRILL_TOKEN}@github.com/Cloudbird-Software/.github.git" ledger -b feishu-ledger 2>/dev/null; then | ||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. governance_token authenticates git push The new drill workflow injects the org-admin GOVERNANCE_TOKEN directly into authenticated Git URLs for ledger clone/push operations instead of using the repository-standard GitHub App token helper. This bypasses the required App identity and uses the governance PAT for an ordinary repository contents write. Agent Prompt
|
||||||||||||||||||||||||||||||||
| git clone --depth 1 "https://x-access-token:${DRILL_TOKEN}@github.com/Cloudbird-Software/.github.git" ledger | ||||||||||||||||||||||||||||||||
| git -C ledger checkout -b feishu-ledger | ||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||
| BASE="ledger/$SHADOW" | ||||||||||||||||||||||||||||||||
| [[ -f "$BASE" ]] || : > "$BASE" | ||||||||||||||||||||||||||||||||
| python3 governance/evidence_shadow.py relink --base "$BASE" --local "$SHADOW" --out merged.jsonl | ||||||||||||||||||||||||||||||||
| python3 governance/evidence_shadow.py verify --file merged.jsonl | ||||||||||||||||||||||||||||||||
| mkdir -p "ledger/governance/feishu" | ||||||||||||||||||||||||||||||||
|
Comment on lines
+72
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 6. Initial ledger write fails The persistence step creates BASE before creating its parent ledger/governance/feishu directory. On the first feishu-ledger write, that directory is absent and the redirection fails under `set -e`, so no audit chain is committed. Agent Prompt
|
||||||||||||||||||||||||||||||||
| cp merged.jsonl "$BASE" | ||||||||||||||||||||||||||||||||
| git -C ledger add "$SHADOW" | ||||||||||||||||||||||||||||||||
| git -C ledger diff --cached --quiet && { echo "OK 影子无新增——不提交(幂等)"; exit 0; } | ||||||||||||||||||||||||||||||||
| git -C ledger commit -m "feishu: 影子账本追加(IR-0006 W3-F1 演练,链验通过)" | ||||||||||||||||||||||||||||||||
| for i in 1 2 3; do git -C ledger push "https://x-access-token:${DRILL_TOKEN}@github.com/Cloudbird-Software/.github.git" HEAD:refs/heads/feishu-ledger && break | ||||||||||||||||||||||||||||||||
| git -C ledger pull --rebase "https://x-access-token:${DRILL_TOKEN}@github.com/Cloudbird-Software/.github.git" feishu-ledger || true; sleep 5; done | ||||||||||||||||||||||||||||||||
|
Comment on lines
+81
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 7. Failed pushes report success After the third failed git push, the retry loop ends with a successful sleep 5 and has no post-loop failure check. The workflow can therefore finish green although the drill audit commit was never published to feishu-ledger. Agent Prompt
Comment on lines
+81
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 所有 push 重试失败时必须使步骤失败。 每次 建议修改- for i in 1 2 3; do git -C ledger push "https://x-access-token:${DRILL_TOKEN}`@github.com/Cloudbird-Software/.github.git`" HEAD:refs/heads/feishu-ledger && break
- git -C ledger pull --rebase "https://x-access-token:${DRILL_TOKEN}`@github.com/Cloudbird-Software/.github.git`" feishu-ledger || true; sleep 5; done
+ pushed=0
+ for _ in 1 2 3; do
+ if git -C ledger push "https://x-access-token:${DRILL_TOKEN}`@github.com/Cloudbird-Software/.github.git`" HEAD:refs/heads/feishu-ledger; then
+ pushed=1
+ break
+ fi
+ git -C ledger pull --rebase "https://x-access-token:${DRILL_TOKEN}`@github.com/Cloudbird-Software/.github.git`" feishu-ledger || true
+ sleep 5
+ done
+ if [[ "$pushed" -ne 1 ]]; then
+ echo "::error::影子账本 push 在 3 次重试后仍失败" >&2
+ exit 2
+ fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| #!/usr/bin/env bash | ||
| # evidence-query.sh —— 四源统一证据查询(IR-0006 W1-B2 / BEH-03 / ADR-0103,AC-4a) | ||
| # evidence-query.sh —— 六源统一证据查询(IR-0006 W1-B2/W3-F1 / BEH-03 / ADR-0103,AC-4a) | ||
| # | ||
| # 一条命令跨源拉取 schema v1 影子账本、逐源验链(fail-closed:链断=红)、 | ||
| # 按时间归并输出统一 JSONL(stdout)+ 分源统计(stderr): | ||
|
|
@@ -11,6 +11,10 @@ | |
| # 源 5 tickets Cloudbird-Software/cnb-bridge @ tickets-ledger tickets.jsonl | ||
| # (W2-C1 内网调度器短票据 grant/revoke——AC-5b 统一账本;Go 发射器产出, | ||
| # 链形态与 evidence_shadow.py 逐字节兼容,金向量锚定) | ||
| # 源 6 feishu Cloudbird-Software/.github @ feishu-ledger governance/feishu/shadow-evidence.jsonl | ||
| # (W3-F1 飞书多维表格投影同步/对账/重建演练事件——payload 带每轮 api_calls | ||
| # 计数=AC-7a 调用账本可查询锚点;日常 15min 轮影子随 runner 销毁=丢弃层, | ||
| # 本源只含 drill 持久化轮) | ||
| # | ||
| # 用法: | ||
| # bash governance/evidence-query.sh [--card owner/repo#n] [--json] # --json=汇总行也走 stdout | ||
|
|
@@ -74,21 +78,23 @@ DRILL_OK=0; fetch_file "Cloudbird-Software/.github" "drill-ledger" "governance/d | |
| BUTLER_OK=0; fetch_file "Cloudbird-Software/.github" "butler-ledger" "governance/butler/shadow-evidence.jsonl" "$TMP/butler.jsonl" && BUTLER_OK=1 || [[ $? -eq 1 ]] || exit 2 | ||
| ELEV_OK=0; fetch_file "Cloudbird-Software/.github" "elevation-ledger" "governance/elevation/shadow-evidence.jsonl" "$TMP/elev.jsonl" && ELEV_OK=1 || [[ $? -eq 1 ]] || exit 2 | ||
| TICKET_OK=0; fetch_file "Cloudbird-Software/cnb-bridge" "tickets-ledger" "tickets.jsonl" "$TMP/tickets.jsonl" && TICKET_OK=1 || [[ $? -eq 1 ]] || exit 2 | ||
| FEISHU_OK=0; fetch_file "Cloudbird-Software/.github" "feishu-ledger" "governance/feishu/shadow-evidence.jsonl" "$TMP/feishu.jsonl" && FEISHU_OK=1 || [[ $? -eq 1 ]] || exit 2 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 8. Malformed source silently omitted The new Feishu source is marked available even when decoding its successful API response fails, because fetch_file() unconditionally returns 0 after the Python decoder. The merge then skips the absent/empty file and returns success, silently omitting the sixth ledger instead of failing closed. Agent Prompt
|
||
|
|
||
| # ---- 逐源验链 + 归并输出(链断=exit 3:不可信数据不出结果) ---- | ||
| export CARD_FILTER JSON_ONLY DRILL_OK BUTLER_OK ELEV_OK TICKET_OK | ||
| python3 - "$DIR/evidence_shadow.py" "$SRC_METER" "$TMP/drill.jsonl" "$TMP/butler.jsonl" "$TMP/elev.jsonl" "$TMP/tickets.jsonl" "$TMP" <<'PYEOF' | ||
| export CARD_FILTER JSON_ONLY DRILL_OK BUTLER_OK ELEV_OK TICKET_OK FEISHU_OK | ||
| python3 - "$DIR/evidence_shadow.py" "$SRC_METER" "$TMP/drill.jsonl" "$TMP/butler.jsonl" "$TMP/elev.jsonl" "$TMP/tickets.jsonl" "$TMP/feishu.jsonl" "$TMP" <<'PYEOF' | ||
| import glob, json, os, sys | ||
|
|
||
| sys.path.insert(0, os.path.dirname(os.path.abspath(sys.argv[1]))) | ||
| import evidence_shadow # noqa: E402 验链与 CI-Workflows 侧同源语义 | ||
|
|
||
| metering_dir, drill_f, butler_f, elev_f, tickets_f, tmp = sys.argv[2:8] | ||
| metering_dir, drill_f, butler_f, elev_f, tickets_f, feishu_f, tmp = sys.argv[2:9] | ||
| sources = {"metering": sorted(glob.glob(os.path.join(metering_dir, "shadow-evidence-*.jsonl"))), | ||
| "drill": [drill_f] if os.environ.get("DRILL_OK") == "1" else [], | ||
| "butler": [butler_f] if os.environ.get("BUTLER_OK") == "1" else [], | ||
| "elevation": [elev_f] if os.environ.get("ELEV_OK") == "1" else [], | ||
| "tickets": [tickets_f] if os.environ.get("TICKET_OK") == "1" else []} | ||
| "tickets": [tickets_f] if os.environ.get("TICKET_OK") == "1" else [], | ||
| "feishu": [feishu_f] if os.environ.get("FEISHU_OK") == "1" else []} | ||
| errs, recs = [], [] | ||
| for src, files in sources.items(): | ||
| for f in files: | ||
|
|
@@ -111,7 +117,7 @@ for r in out: | |
|
|
||
| summary = { | ||
| "total": len(out), | ||
| "by_source": {s: sum(1 for r in out if r["source"] == s) for s in ("metering", "drill", "butler", "elevation", "tickets")}, | ||
| "by_source": {s: sum(1 for r in out if r["source"] == s) for s in ("metering", "drill", "butler", "elevation", "tickets", "feishu")}, | ||
| "by_tenant": {}, | ||
| "by_card_top": {}, | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5. Drill races scheduled sync
🐞 Bug☼ ReliabilityAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools