From e9563879b4f1f487fe5e3e7b89ad2934ab1714d6 Mon Sep 17 00:00:00 2001 From: lml2468 Date: Sat, 27 Jun 2026 18:22:03 +0800 Subject: [PATCH 1/2] chore: remove octo-issue-notify / octo-pr-review-feed / octo-pr-result-notify reusable workflows The multica triage chain that consumed these reusable workflows is being decommissioned in favor of a loop-engineering pattern. All 27 caller workflows across Mininglamp-OSS repos have been removed in parallel; the multica autopilots, workflow skills, and per-repo TRIAGE_WEBHOOK_URL / PR_TRIAGE_WEBHOOK_URL secrets are being torn down too. No remaining caller references these three reusable workflows. Removing them keeps the .github repo lean and prevents accidental future use. Kept (used by other chains, NOT in scope of this decommissioning): - issue-welcome.yml - octo-ci-status.yml - reusable-* (check-sprint / dependency-review / history-check / pr-labeler / pr-title-lint / stale) - octo-notify composite action (still used by issue-welcome and octo-ci-status) --- .github/workflows/octo-issue-notify.yml | 164 ------------------ .github/workflows/octo-pr-result-notify.yml | 178 -------------------- .github/workflows/octo-pr-review-feed.yml | 154 ----------------- 3 files changed, 496 deletions(-) delete mode 100644 .github/workflows/octo-issue-notify.yml delete mode 100644 .github/workflows/octo-pr-result-notify.yml delete mode 100644 .github/workflows/octo-pr-review-feed.yml diff --git a/.github/workflows/octo-issue-notify.yml b/.github/workflows/octo-issue-notify.yml deleted file mode 100644 index 7b7f37d..0000000 --- a/.github/workflows/octo-issue-notify.yml +++ /dev/null @@ -1,164 +0,0 @@ -# Reusable workflow: notify Octo IM when an issue is opened, and forward the -# event to the triage agent (optional). -# -# Refactored (Wave 2) to the two-stage shape: this workflow does the MAPPING -# (sanitize + format the IM message, build the webhook JSON), and delegates -# TRANSPORT to the shared `octo-notify` composite action (POST + retry/backoff, -# IM allowlist). See docs/workflow-architecture.md §4a + Plane 6. -# -# Event policy: only `opened` is forwarded (unified IM + webhook trigger). The -# guard below enforces this centrally even if a caller still subscribes to -# `reopened`/others. (This narrows the old [opened, reopened] behavior — intended.) -# -# Triage webhook (optional): pass the TRIAGE_WEBHOOK_URL secret to forward the -# event to the triage agent, which classifies the issue (labels + a triage -# comment). The URL is a capability secret — never hardcode it; pass from a -# secret. The agent fetches issue details itself via the GitHub API using -# repo + number, so the body is NOT egressed through Actions. -# -# This is the canonical reusable for issue notification + triage. (It replaced -# the legacy octo-issue-feed.yml, whose back-compat shim was removed in v1.1.0 -# once all callers migrated to octo-issue-notify.yml@v1.) -name: Octo Issue Notify (reusable) - -on: - workflow_call: - inputs: - repo_name: - type: string - required: true - issue_number: - type: number - required: true - issue_title: - type: string - required: true - issue_url: - type: string - required: true - issue_author: - type: string - required: true - event_action: - type: string - required: true - api_base_url: - type: string - required: false - default: 'https://im.deepminer.com.cn/api' - description: 'Octo IM API base URL. Only the production endpoint is allowlisted.' - feed_group_id: - type: string - required: false - default: '151a45970e1546afa9e947ac36a5c4e5' - description: 'Octo IM group ID for the central issue feed channel.' - enable_im_notify: - type: boolean - required: false - default: true - description: >- - When false, skip the Octo IM push and only fire the triage webhook. - Default true preserves existing behavior for all current callers; opt - in by passing `enable_im_notify: false` when a repo has already moved - to an external triage agent and no longer wants duplicate IM pings. - secrets: - OCTO_BOT_TOKEN: - required: true - TRIAGE_WEBHOOK_URL: - required: false - description: >- - Triage agent webhook URL (capability secret). When provided, the issue - event is forwarded to the agent for classification. Omit to disable. - -permissions: {} - -jobs: - notify: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Build IM message and webhook payload - id: build - env: - REPO_NAME: ${{ inputs.repo_name }} - ISSUE_NUMBER: ${{ inputs.issue_number }} - ISSUE_TITLE: ${{ inputs.issue_title }} - ISSUE_URL: ${{ inputs.issue_url }} - ISSUE_AUTHOR: ${{ inputs.issue_author }} - EVENT_ACTION: ${{ inputs.event_action }} - run: | - python3 - <<'PYEOF' - import os, json, re, sys - - OUT = os.environ['GITHUB_OUTPUT'] - DELIM = '__OCTO_NOTIFY_EOF_9f3a__' - - def emit(key, value): - with open(OUT, 'a') as f: - f.write(f'{key}<<{DELIM}\n{value}\n{DELIM}\n') - - def require_env(name): - val = os.environ.get(name, '').strip() - if not val: - print(f'ERROR: required environment variable {name} is missing or empty') - sys.exit(2) - return val - - def sanitize_text(s, max_len=300): - """Strip control characters to prevent IM message injection.""" - s = str(s or '') - s = re.sub(r'[\x00-\x1f\x7f]', ' ', s) - return s[:max_len] - - def require_repo_name(name): - """Validate repo name to prevent path traversal / injection.""" - val = require_env(name) - if not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9._-]{0,99}', val) or val in {'.', '..'}: - print(f'ERROR: {name} contains invalid characters: {val!r}') - sys.exit(2) - return val - - action = require_env('EVENT_ACTION') - - # Unified event policy: only `opened` triggers IM + triage. - if action != 'opened': - print(f'Skipping event_action={action!r} — only opened is forwarded.') - emit('skip', 'true') - sys.exit(0) - - repo = require_repo_name('REPO_NAME') - num = require_env('ISSUE_NUMBER') - title = sanitize_text(require_env('ISSUE_TITLE'), max_len=300) - url = require_env('ISSUE_URL') - author = sanitize_text(require_env('ISSUE_AUTHOR'), max_len=80) - - # IM message (mapping stays here; transport is octo-notify) - im_message = f"🆕 [{repo}] Issue #{num} · {title}\n👤 {author}\n🔗 {url}" - - # Webhook payload for the triage agent. Minimal identifying fields — - # the agent fetches full issue details via the GitHub API itself, so - # the issue body is not egressed through Actions. - webhook_payload = json.dumps({ - 'repo': repo, - 'number': int(num), - 'title': title, - 'url': url, - 'author': author, - 'action': action, - }) - - emit('skip', 'false') - emit('im_message', im_message) - emit('webhook_payload', webhook_payload) - PYEOF - - - name: Send (IM feed + optional triage webhook) - if: steps.build.outputs.skip != 'true' - uses: Mininglamp-OSS/.github/.github/actions/octo-notify@v1 - with: - im-message: ${{ inputs.enable_im_notify && steps.build.outputs.im_message || '' }} - im-token: ${{ secrets.OCTO_BOT_TOKEN }} - im-group-id: ${{ inputs.feed_group_id }} - im-api-base: ${{ inputs.api_base_url }} - webhook-url: ${{ secrets.TRIAGE_WEBHOOK_URL }} - webhook-payload: ${{ steps.build.outputs.webhook_payload }} diff --git a/.github/workflows/octo-pr-result-notify.yml b/.github/workflows/octo-pr-result-notify.yml deleted file mode 100644 index d866f12..0000000 --- a/.github/workflows/octo-pr-result-notify.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Octo PR Result Notify (reusable) - -# Refactored (Wave 2): MAPPING (validate + sanitize + format message) stays -# here; TRANSPORT delegated to the shared octo-notify composite action. -# See docs/workflow-architecture.md Plane 6. - -on: - workflow_call: - inputs: - repo_name: - type: string - required: true - pr_number: - type: number - required: true - pr_title: - type: string - required: true - pr_url: - type: string - required: true - pr_author: - type: string - required: true - event_kind: - type: string - required: true - reviewer: - type: string - required: false - default: '' - pr_additions: - type: number - required: false - default: 0 - pr_deletions: - type: number - required: false - default: 0 - pr_changed_files: - type: number - required: false - default: 0 - feed_group_id: - type: string - required: false - default: '1c303c142e9840f2a9b46c10b0972e8d' - api_base_url: - type: string - required: false - default: 'https://im.deepminer.com.cn/api' - secrets: - OCTO_BOT_TOKEN: - required: true - -permissions: {} - -jobs: - notify: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Build result message - id: build - env: - REPO_NAME: ${{ inputs.repo_name }} - PR_NUMBER: ${{ inputs.pr_number }} - PR_TITLE: ${{ inputs.pr_title }} - PR_URL: ${{ inputs.pr_url }} - PR_AUTHOR: ${{ inputs.pr_author }} - EVENT_KIND: ${{ inputs.event_kind }} - REVIEWER: ${{ inputs.reviewer }} - PR_ADDITIONS: ${{ inputs.pr_additions }} - PR_DELETIONS: ${{ inputs.pr_deletions }} - PR_CHANGED_FILES: ${{ inputs.pr_changed_files }} - FEED_GROUP_ID: ${{ inputs.feed_group_id }} - run: | - python3 - <<'PYEOF' - import os, re, sys - - OUT = os.environ['GITHUB_OUTPUT'] - DELIM = '__OCTO_NOTIFY_EOF_9f3a__' - - def emit(key, value): - with open(OUT, 'a') as f: - f.write(f'{key}<<{DELIM}\n{value}\n{DELIM}\n') - - ALLOWED_KINDS = { - "pr_merged", "pr_closed", - "review_approved", "review_changes_requested", - } - - def require_env(name): - value = os.environ.get(name, "").strip() - if not value: - print(f"::error::Missing required env var: {name}") - sys.exit(1) - return value - - def get_env(name, default=""): - return os.environ.get(name, default).strip() - - def require_group_id(name): - val = os.environ.get(name, '').strip() - if not re.fullmatch(r'[0-9a-f]{32}', val or ''): - print(f'ERROR: {name} must be a 32-char lowercase hex group id') - sys.exit(2) - return val - - def require_repo_name(name): - val = os.environ.get(name, '').strip() - if not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9._-]{0,99}', val or '') or val in {'.', '..'}: - print(f'ERROR: {name} contains invalid characters: {val!r}') - sys.exit(2) - return val - - def sanitize_text(s, max_len=300): - s = str(s or '') - s = re.sub(r'[\x00-\x1f\x7f]', ' ', s) - return s[:max_len] - - repo_name = require_repo_name('REPO_NAME') - pr_number = require_env("PR_NUMBER") - pr_title = sanitize_text(require_env("PR_TITLE")) - pr_url = require_env("PR_URL") - pr_author = sanitize_text(require_env('PR_AUTHOR'), max_len=80) - event_kind = require_env("EVENT_KIND") - reviewer = sanitize_text(get_env('REVIEWER'), max_len=80) - reviewer_display = reviewer if reviewer else "(unknown)" - pr_additions = int(get_env("PR_ADDITIONS", "0") or "0") - pr_deletions = int(get_env("PR_DELETIONS", "0") or "0") - pr_changed_files = int(get_env("PR_CHANGED_FILES", "0") or "0") - # Validate group id format (transport allowlists the API base itself). - require_group_id("FEED_GROUP_ID") - - if event_kind not in ALLOWED_KINDS: - print(f"::warning::Unrecognized event_kind '{event_kind}', skipping") - emit('skip', 'true') - sys.exit(0) - - if event_kind == "pr_merged": - stats_part = f' · +{pr_additions} -{pr_deletions} · {pr_changed_files} files' if (pr_additions or pr_deletions or pr_changed_files) else '' - message = ( - f"\U0001f7e2 [{repo_name}] PR #{pr_number} merged · {pr_title}\n" - f"\U0001f464 {pr_author}{stats_part}\n" - f"\U0001f517 {pr_url}" - ) - elif event_kind == "pr_closed": - message = ( - f"\U0001f534 [{repo_name}] PR #{pr_number} closed · {pr_title}\n" - f"\U0001f464 {pr_author}\n" - f"\U0001f517 {pr_url}" - ) - elif event_kind == "review_approved": - message = ( - f"✅ [{repo_name}] PR #{pr_number} approved · {pr_title}\n" - f"\U0001f464 reviewer: {reviewer_display}\n" - f"\U0001f517 {pr_url}" - ) - elif event_kind == "review_changes_requested": - message = ( - f"\U0001f501 [{repo_name}] PR #{pr_number} changes requested · {pr_title}\n" - f"\U0001f464 reviewer: {reviewer_display}\n" - f"\U0001f517 {pr_url}" - ) - - emit('skip', 'false') - emit('im_message', message) - PYEOF - - - name: Send to Octo IM - if: steps.build.outputs.skip != 'true' - uses: Mininglamp-OSS/.github/.github/actions/octo-notify@v1 - with: - im-message: ${{ steps.build.outputs.im_message }} - im-token: ${{ secrets.OCTO_BOT_TOKEN }} - im-group-id: ${{ inputs.feed_group_id }} - im-api-base: ${{ inputs.api_base_url }} diff --git a/.github/workflows/octo-pr-review-feed.yml b/.github/workflows/octo-pr-review-feed.yml deleted file mode 100644 index 7a1a483..0000000 --- a/.github/workflows/octo-pr-review-feed.yml +++ /dev/null @@ -1,154 +0,0 @@ -name: Octo PR Review Feed (reusable) - -# Refactored (Wave 2): MAPPING stays here; TRANSPORT delegated to octo-notify. -# See docs/workflow-architecture.md Plane 6. - -on: - workflow_call: - inputs: - repo_name: - type: string - required: true - pr_number: - type: number - required: true - pr_title: - type: string - required: true - pr_url: - type: string - required: true - pr_author: - type: string - required: true - event_action: - type: string - required: true - project_group_id: - type: string - required: true - api_base_url: - type: string - required: false - default: 'https://im.deepminer.com.cn/api' - enable_im_notify: - type: boolean - required: false - default: true - description: >- - When false, skip the Octo IM push and only fire the PR triage webhook. - Default true preserves existing behavior for all current callers; opt - in by passing `enable_im_notify: false` when a repo has already moved - to an external PR triage agent and no longer wants duplicate IM pings. - secrets: - OCTO_BOT_TOKEN: - required: true - PR_TRIAGE_WEBHOOK_URL: - required: false - description: >- - PR review triage agent webhook URL (capability secret). When provided, - the PR ready_for_review / review_requested event is forwarded to the - agent for fan-out review dispatch. Omit to disable. - -permissions: {} - -jobs: - notify: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Build review message - id: build - env: - REPO_NAME: ${{ inputs.repo_name }} - PR_NUMBER: ${{ inputs.pr_number }} - PR_TITLE: ${{ inputs.pr_title }} - PR_URL: ${{ inputs.pr_url }} - PR_AUTHOR: ${{ inputs.pr_author }} - EVENT_ACTION: ${{ inputs.event_action }} - PROJECT_GROUP_ID: ${{ inputs.project_group_id }} - run: | - python3 - <<'PYEOF' - import os, re, sys - - OUT = os.environ['GITHUB_OUTPUT'] - DELIM = '__OCTO_NOTIFY_EOF_9f3a__' - - def emit(key, value): - with open(OUT, 'a') as f: - f.write(f'{key}<<{DELIM}\n{value}\n{DELIM}\n') - - ALLOWED_ACTIONS = {"ready_for_review", "review_requested"} - - def require_env(name): - value = os.environ.get(name, "").strip() - if not value: - print(f"::error::Missing required env var: {name}") - sys.exit(1) - return value - - def require_group_id(name): - val = os.environ.get(name, '').strip() - if not re.fullmatch(r'[0-9a-f]{32}', val or ''): - print(f'ERROR: {name} must be a 32-char lowercase hex group id') - sys.exit(2) - return val - - def require_repo_name(name): - val = os.environ.get(name, '').strip() - if not re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9._-]{0,99}', val or '') or val in {'.', '..'}: - print(f'ERROR: {name} contains invalid characters: {val!r}') - sys.exit(2) - return val - - def sanitize_text(s, max_len=300): - s = str(s or '') - s = re.sub(r'[\x00-\x1f\x7f]', ' ', s) - return s[:max_len] - - repo_name = require_repo_name('REPO_NAME') - pr_number = require_env("PR_NUMBER") - pr_title = sanitize_text(require_env("PR_TITLE")) - pr_url = require_env("PR_URL") - pr_author = sanitize_text(require_env('PR_AUTHOR'), max_len=80) - event_action = require_env("EVENT_ACTION") - require_group_id("PROJECT_GROUP_ID") - - if event_action not in ALLOWED_ACTIONS: - print(f"::warning::Unrecognized event_action '{event_action}', skipping") - emit('skip', 'true') - sys.exit(0) - - emoji = {"ready_for_review": "✅", "review_requested": "\U0001f440"}[event_action] - - message = ( - f"{emoji} [{repo_name}] PR #{pr_number} · {pr_title}\n" - f"\U0001f464 {pr_author}\n" - f"\U0001f517 {pr_url}" - ) - - import json - webhook_payload = json.dumps({ - 'repo': repo_name, - 'number': int(pr_number), - 'title': pr_title, - 'url': pr_url, - 'author': pr_author, - 'action': event_action, - }) - - emit('skip', 'false') - emit('im_message', message) - emit('webhook_payload', webhook_payload) - PYEOF - - - name: Send (IM feed + optional triage webhook) - if: steps.build.outputs.skip != 'true' - uses: Mininglamp-OSS/.github/.github/actions/octo-notify@v1 - with: - im-message: ${{ inputs.enable_im_notify && steps.build.outputs.im_message || '' }} - im-token: ${{ secrets.OCTO_BOT_TOKEN }} - im-group-id: ${{ inputs.project_group_id }} - im-api-base: ${{ inputs.api_base_url }} - webhook-url: ${{ secrets.PR_TRIAGE_WEBHOOK_URL }} - webhook-payload: ${{ steps.build.outputs.webhook_payload }} From 3eac1184530e48813e6c94dcc0234d3bc213f311 Mon Sep 17 00:00:00 2001 From: lml2468 Date: Sat, 27 Jun 2026 18:33:02 +0800 Subject: [PATCH 2/2] ci: nudge for re-review (no code change)