chore(ci): add org governance workflow suite#9
Conversation
yujiawei
left a comment
There was a problem hiding this comment.
Code Review — PR #9 (octo-cli)
Summary
Adds the standard org governance workflow suite (12 caller workflows under .github/workflows/) that thinly wrap reusable workflows centrally maintained in Mininglamp-OSS/.github. The PR is purely additive (+256 / -0, no existing files changed) and follows the same caller pattern already deployed in sibling repos (octo-server, octo-deployment, octo-web, octo-adapters, etc.).
I cross-checked every caller against the reusable workflow it invokes and against Mininglamp-OSS/octo-cli's existing layout. No correctness or security blockers.
1. Verification
| Caller | Reusable target exists | Inputs match | Secrets match | Permissions |
|---|---|---|---|---|
auto-add-to-project.yml |
✅ auto-add-to-project.yml@main |
✅ none required | ✅ PROJECT_TOKEN forwarded |
✅ |
codeql.yml |
✅ reusable-codeql.yml@main |
✅ language: go (octo-cli is a Go module, CI matrix 1.24.x) |
n/a | ✅ actions:read / contents:read / security-events:write |
issue-welcome.yml |
✅ issue-welcome.yml@main |
✅ none | n/a | ✅ issues:write |
labeler.yml |
✅ reusable-pr-labeler.yml@main |
✅ pr_number / repo_owner / repo_name |
n/a | ✅ issues:write / pull-requests:write |
octo-ci-status.yml |
✅ octo-ci-status.yml@main |
✅ all 7 inputs (repo_name / workflow_name / conclusion / run_id / run_url / project_group_id / workflow_id); existing ci.yml is named CI, matching the workflows: ["CI"] filter |
✅ OCTO_BOT_TOKEN |
✅ actions:read |
octo-issue-feed.yml |
✅ octo-issue-feed.yml@main |
✅ all 6 inputs | ✅ OCTO_BOT_TOKEN |
✅ |
octo-pr-feed.yml |
✅ octo-pr-feed.yml@main |
✅ all 12 inputs | ✅ OCTO_BOT_TOKEN |
✅ |
pr-contributor-welcome.yml |
✅ reusable-pr-contributor-welcome.yml@main |
✅ none | n/a | ✅ pull-requests:write |
release-drafter.yml |
✅ reusable-release-drafter.yml@main |
✅ config-name optional |
n/a | ✅ contents:write / pull-requests:read |
release-publish.yml |
✅ reusable-release-publish.yml@main |
✅ tag / validate_run_id / draft |
n/a | ✅ contents:write / actions:read |
stale.yml |
✅ reusable-stale.yml@main |
✅ all optional with defaults | n/a | ✅ issues:write / pull-requests:write |
workflow-sanity.yml |
✅ workflow-sanity.yml@main |
✅ none | n/a | ✅ |
2. Security
- All
pull_request_targettriggers (auto-add-to-project,labeler,octo-pr-feed,pr-contributor-welcome) avoid checking out PR head refs and only forward metadata/numbers to reusable workflows that hit the GitHub API. The reusable side likewise does not runactions/checkoutagainst the PR. The# zizmor: ignore[dangerous-triggers]annotations onlabeler.ymlandpr-contributor-welcome.ymlare accompanied by a justification comment, which is the right pattern. - Top-level
permissions: {}is set on every caller (least privilege), and only the called job declares the writes it needs. Good. octo-pr-feed.ymlcorrectly skips draft PRs withif: ${{ !github.event.pull_request.draft }}, which prevents leaking work-in-progress titles to the IM feed.codeql.ymlskips draft PRs (!github.event.pull_request.draft) and usesconcurrency.cancel-in-progress: trueonly for PR runs, preserving main-branch and scheduled runs — correct.octo-ci-status.ymllistens onworkflow_runfiltered tomainandcompleted;conclusionwill always be set when the type iscompleted, so the reusable's requiredconclusioninput is safe.
3. Findings
P0 / P1
None.
P2 / nits / maintainability (non-blocking)
-
No
.github/release-drafter.ymlconfig in this repo.reusable-release-drafter.ymldefaults to looking uprelease-drafter.ymlunder.github/. Therelease-drafteraction falls back to a built-in default schema if the config is missing, so this won't fail — but the resulting release notes will be uncategorized. Consider following up with a config that mirrors what other org repos use. -
Coexistence of
release.yml(existing) andrelease-publish.yml(new). The repo already hasrelease.ymlthat runs goreleaser on tag push. The newrelease-publish.ymlisworkflow_dispatch-only and goes through the org reusable that just flips a GitHub Release (no binaries). They don't collide (different names, different triggers), but the relationship isn't documented. Suggest a short note in the PR description (or a comment inrelease-publish.yml) clarifying that goreleaser produces the binaries on tag push andrelease-publish.ymlis the manual "promote draft → published" lever — otherwise future maintainers may delete one thinking it's redundant. -
Pinning reusable workflows to
@main. Every caller pinsMininglamp-OSS/.github/...@main. This is the established pattern across sibling repos and is mitigated by org-level control of.github, but it does mean any breaking change in the central repo lands in every caller simultaneously. Worth tracking as a future hardening item (move to tagged@v1once the reusable suite stabilizes). -
stale.ymlaccepts all defaults (14d/7d issues, 14d/7d PRs). Reasonable starting point; revisit if the project picks up enough open issues/PRs to need different cadences. -
octo-pr-feed.ymlpassesfeed_group_id: "1c303c142e9840f2a9b46c10b0972e8d"explicitly even though the reusable defaults to the same value. Harmless, but if the org ever wants to swap the default channel centrally, every caller will need an edit. Optional: drop the explicitfeed_group_idline and let the default ride.
4. Additional observations
actions/checkoutis intentionally absent from every caller in this PR (the reusables either don't need it or do their own pinned checkout), which is the correct pattern forpull_request_target. No change needed.- Schedules don't collide with each other or with existing CI: CodeQL
0 6 * * *, stale0 3 * * *, andocto-ci-statusis event-driven onworkflow_run. - The
if: github.event_name != 'pull_request' || !github.event.pull_request.draftguard incodeql.ymlis the same pattern used inocto-server— consistent.
Verdict
The 12 workflows are correctly wired, minimally permissioned, and consistent with the rest of the organization's CI/CD governance rollout. Ship it; the items above are follow-up suggestions, not merge blockers.
Required by release-drafter action. Without this config, every push to main triggers a failing Release Drafter run. Config copied from octo-server (org standard template).
The reusable workflow uses issues.createComment API which requires issues: write, not pull-requests: write. With workflow_call, the caller's permissions are what the token receives.
octo-cli has CodeQL default setup enabled in repo settings. Advanced configuration (workflow file) conflicts with default setup. Error: 'CodeQL analyses from advanced configurations cannot be processed when the default setup is enabled'
This workflow was copied with octo-server's project_group_id which would send CI notifications to the wrong Octo group. Will be re-added when a proper project group is configured for this repo.
yujiawei
left a comment
There was a problem hiding this comment.
Code Review — PR #9 (octo-cli)
Summary
This PR adds 11 caller workflows + 1 release-drafter config that delegate to centralized reusable workflows in Mininglamp-OSS/.github. The wiring is correct: every caller matches its reusable workflow's workflow_call input/secret signature, pull_request_target triggers never check out PR code (with # zizmor: ignore[dangerous-triggers] markers and explanatory comments on the two sensitive ones), and job-level permissions: correctly scope the inherited GITHUB_TOKEN. actionlint runs clean across all 11 files; the bundled workflow-sanity.yml will keep it that way going forward.
No P0/P1 issues found. A handful of P2/nit items below — none blocking.
1. Verification
| Check | Result | Evidence |
|---|---|---|
| Caller→reusable input contracts match | ✅ | All 6 callers that pass with:/secrets: align with the reusable signatures (e.g. octo-pr-feed.yml lines 12-24 vs. reusable workflow_call.inputs block; octo-issue-feed.yml lines 11-18 vs. reusable inputs; reusable-pr-labeler.yml requires pr_number/repo_owner/repo_name and caller labeler.yml:21-23 supplies all three) |
actionlint |
✅ | actionlint .github/workflows/*.yml → exit 0 |
| No tabs in YAML | ✅ | Sanity check (matches workflow-sanity.yml rule) |
pull_request_target safety |
✅ | None of the new callers check out PR code; all delegate to reusable workflows that are API-only. auto-add-to-project.yml, octo-pr-feed.yml, labeler.yml, pr-contributor-welcome.yml — verified |
| Permission scoping | ✅ | All workflows use top-level permissions: {} (except issue-welcome.yml, see N1) and grant the minimum the called workflow needs at the job level |
| Secret passthrough | ✅ | PROJECT_TOKEN, OCTO_BOT_TOKEN declared required: true in reusables and supplied by callers |
| Hardcoded group IDs | ✅ | project_group_id: 9ea115c7462b4b45b8c85d07d07e0dde matches the reusable's 32-char hex validator |
2. Findings
P2-1 — PR description scope mismatch (2 files missing, 1 file undocumented)
The PR body lists 12 added files including codeql.yml and octo-ci-status.yml, but the diff contains neither. Conversely, .github/release-drafter.yml (the config consumed by reusable-release-drafter.yml) is added but not listed.
- Missing from diff:
codeql.yml,octo-ci-status.yml - Undocumented in description:
.github/release-drafter.yml
Recommendation: update the PR description before merge, or land them in a follow-up PR if those two were dropped intentionally. The reusable reusable-codeql.yml exists in Mininglamp-OSS/.github, so dropping CodeQL leaves octo-cli without the SAST coverage other repos in the suite have.
P2-2 — Mininglamp-OSS/.github@main not pinned
All 11 callers reference reusable workflows at @main:
uses: Mininglamp-OSS/.github/.github/workflows/reusable-pr-labeler.yml@mainThe reusable workflow's own header comment (e.g. auto-add-to-project.yml) gives the example as @v1. @main means a force-push or a bad merge in .github immediately propagates to every consumer repo, including this one — there is no rollback window. For an internal org-owned repo this is a tolerable risk; pinning to a tag (@v1) or commit SHA would harden it. Matching whatever pattern the other ~8 known callers (octo-server, octo-web, …) use would be ideal for consistency.
P2-3 — Potential interaction between existing release.yml (goreleaser) and new release-publish.yml
.github/workflows/release.yml (unchanged on this branch) runs goreleaser on every v* tag push and creates the GitHub Release. The new release-publish.yml is workflow_dispatch only and calls reusable-release-publish.yml, which upserts the release with generate_release_notes=true (lines 1061-1080 of the reusable).
If an operator manually triggers release-publish.yml for a tag that goreleaser already published, the reusable's PATCH path will overwrite at least draft and tag_name (and potentially regenerate notes). Goreleaser's notes / asset metadata could be lost. Recommend documenting the intended split — e.g. "release-publish.yml is for tags published outside goreleaser; do not invoke for goreleaser-published tags" — or making them mutually exclusive (e.g. a guard checking for an existing release with assets).
N1 — Style: missing permissions: {} in issue-welcome.yml
Every other new caller declares permissions: {} at the workflow top level for principle-of-least-privilege; issue-welcome.yml omits it and relies on the per-job permissions: issues: write. Add permissions: {} at the top level for consistency with the other 10 files in this PR.
N2 — workflow-sanity.yml push: paths drop .github/actions/**
push:
branches: [main]
paths:
- '.github/workflows/**'The reusable workflow itself watches both .github/workflows/** and .github/actions/** for push, and the caller's own pull_request block correctly includes both. Adding .github/actions/** to the push paths keeps sanity coverage consistent for any composite action that might land here later. Pure consistency nit — octo-cli has no .github/actions/ directory today.
N3 — feed_group_id redundantly passed in octo-pr-feed.yml
octo-pr-feed.yml:22 passes feed_group_id: "1c303c142e9840f2a9b46c10b0972e8d", which is exactly the reusable's default:. Drop the explicit value to let the reusable own the constant (one less place to change if the IM channel ever moves).
3. Suggestions
- Fix the description / scope mismatch in P2-1 (re-add
codeql.yml+octo-ci-status.yml, or amend the body). - After this lands, consider a small follow-up that pins all
@mainrefs to a tag (P2-2) — easier to do once the new files are in than as part of this PR. - Document the release.yml ↔ release-publish.yml split (P2-3) in
CONTRIBUTING.mdor as a comment inrelease-publish.yml.
4. Additional observations
- Reusable workflow comments explicitly forbid adding
actions/checkoutto thepull_request_targetreusables. None of the new callers violate this. labeler.ymlandpr-contributor-welcome.ymlcarry# zizmor: ignore[dangerous-triggers]with a one-line justification — good practice; matches the security-audit checklist.octo-pr-feed.ymlhasif: ${{ !github.event.pull_request.draft }}, which correctly avoids noisy notifications during draft work.- The release-drafter config (
.github/release-drafter.yml)change-templateuses@$AUTHOR, which will render as a clickable GitHub mention in release notes — that is intentional / standard for this tool.
project_group_id is required and repo-specific. Copied octo-server's ID which would send PR notifications to wrong Octo group. Will re-add when proper project group is configured for this repo.
yujiawei
left a comment
There was a problem hiding this comment.
Code Review — PR #9 (octo-cli)
Summary
This PR wires octo-cli into the org-standard governance workflow suite (release drafting, labeler, stale, issue/PR welcome, CodeQL-style sanity, release publish, project auto-add, issue feed). All added workflows are thin wrappers that delegate to reusable workflows in Mininglamp-OSS/.github, which is consistent with the pattern already used in sibling repos (e.g. octo-server).
I verified that every reusable workflow referenced in this PR exists at Mininglamp-OSS/.github/.github/workflows@main:
| Caller | Callee | Exists |
|---|---|---|
auto-add-to-project.yml |
auto-add-to-project.yml |
✅ |
issue-welcome.yml |
issue-welcome.yml |
✅ |
labeler.yml |
reusable-pr-labeler.yml |
✅ |
octo-issue-feed.yml |
octo-issue-feed.yml |
✅ |
pr-contributor-welcome.yml |
reusable-pr-contributor-welcome.yml |
✅ |
release-drafter.yml |
reusable-release-drafter.yml |
✅ |
release-publish.yml |
reusable-release-publish.yml |
✅ |
stale.yml |
reusable-stale.yml |
✅ |
workflow-sanity.yml |
workflow-sanity.yml |
✅ |
No P0 (correctness/security/data-loss/build-break) or P1 (functional bug) issues found. A handful of P2 nits and one documentation discrepancy below.
Findings
P2 — PR description lists 3 files that are not in the diff
The PR body's "Files Added" list contains 12 workflow files, but the diff only adds 10. The following are listed in the description but are not present in the diff:
.github/workflows/codeql.yml.github/workflows/octo-ci-status.yml.github/workflows/octo-pr-feed.yml
Sibling repo octo-server ships all three. If they are intentionally deferred to a follow-up PR, please update the description so reviewers (and any downstream automation that diffs description vs. tree) don't get misled. If the omission is accidental, please add them — octo-pr-feed.yml in particular is the counterpart to the issue feed you are wiring up here.
CodeQL is currently running on this PR via GitHub's default code scanning UI, not a workflow file in the repo, so visibility of the configuration is reduced — adding codeql.yml would put the rule set under code review and version control like the other repos.
P2 — issue-welcome.yml missing top-level permissions: {}
Every other new workflow in this PR declares permissions: {} at the workflow level and then grants the minimum scope at the job level (defense-in-depth: if a future job is added without an explicit permissions: block, it inherits the empty default rather than the legacy permissive default). issue-welcome.yml is the only exception:
# .github/workflows/issue-welcome.yml
name: Issue Welcome
on:
issues:
types: [opened]
jobs: # <-- no top-level `permissions: {}`
welcome:
permissions:
issues: write
uses: Mininglamp-OSS/.github/.github/workflows/issue-welcome.yml@mainSuggest adding permissions: {} between on: and jobs: for consistency with the other 9 files in this PR.
P2 — stale.yml schedules on the :00 minute
# .github/workflows/stale.yml:5
schedule:
- cron: "0 3 * * *"If the same governance suite lands in every Mininglamp-OSS repo, all stale runs will queue at exactly 03:00 UTC. GitHub-hosted runner pickup tends to be lumpy at round-minute crons. Consider staggering (e.g. "17 3 * * *") or randomizing per-repo. Strictly cosmetic — non-blocking.
P2 — Reusable workflows pinned to @main
All 9 callers pin to @main rather than an immutable SHA:
uses: Mininglamp-OSS/.github/.github/workflows/<x>.yml@mainThis matches the existing org pattern, so I'm not asking to change it in this PR. Flagging only as a long-term posture note: any breaking change or compromise on Mininglamp-OSS/.github@main propagates instantly to every consumer with no rollback signal. A future hardening pass could move to SHA pins with an automated bumper (Dependabot for actions: supports reusable workflow refs).
P2 — Style: permissions: after with: in labeler.yml
# .github/workflows/labeler.yml:21
uses: Mininglamp-OSS/.github/.github/workflows/reusable-pr-labeler.yml@main
with:
pr_number: ${{ github.event.pull_request.number }}
repo_owner: ${{ github.repository_owner }}
repo_name: ${{ github.event.repository.name }}
permissions:
issues: write
pull-requests: writeValid YAML and Actions accepts any key order, but the conventional ordering inside a job is uses → permissions → with → secrets. Other files in this PR follow that ordering. Minor.
Things done well
pull_request_targetis used only where required (labeler, contributor welcome, project add) and each instance has azizmor: ignore[dangerous-triggers]comment explaining why the pattern is safe (no PR code checkout/execution). This is the right way to document the deviation.- Every job declares the minimum permissions explicitly rather than relying on repo defaults.
release-publish.ymlcorrectly gates publish on avalidate_run_idinput, forcing the operator to point at a successful CI run on the tagged commit — that prevents publishing a tag whose code never passed CI.release-drafter.yml(config) covers the org's standard label set includingdependencies-changed(which the labeler workflow above will set automatically), so drafted notes will categorize Dependabot/lockfile bumps correctly.
Verdict
APPROVED. The P2 items above are improvements, not blockers. Recommend the author either update the PR description to match the actual file set, or add the three missing workflow files in a follow-up commit before merge.
Jerry-Xin
left a comment
There was a problem hiding this comment.
Summary
Standard org governance workflow suite — 10 caller workflows + 1 release-drafter config, all delegating to centralized reusable workflows in Mininglamp-OSS/.github. Purely additive (+188/-0), no existing files touched.
CI green (7/7), actionlint passes, CodeQL clean.
Verification
Cross-checked every callee exists at Mininglamp-OSS/.github/.github/workflows@main:
- 9/9 referenced reusable workflows confirmed present ✅
- Permissions model verified: callers declare
permissions: {}top-level + minimum job-level grants (defense-in-depth) pull_request_targetcallers (labeler,pr-contributor-welcome,auto-add-to-project) — confirmed none checkout PR code; metadata-only automationpr-contributor-welcome.ymlcallee only usesissues.createComment()+issues.listComments()—issues: writeis sufficient (no PR-specific API unlike the labeler)- Security model: no
actions/checkoutin any sensitive workflow, idempotency markers present, concurrency groups correct
Non-blocking findings
-
Description/diff mismatch — PR body lists 12 files, diff delivers 10. Missing:
codeql.yml,octo-ci-status.yml,octo-pr-feed.yml. All three have reusable counterparts available in.github. Intentional deferral should be noted in description; if accidental,octo-pr-feed.ymlis the most impactful gap (issue feed without PR feed = asymmetric notification coverage). -
issue-welcome.ymlmissing top-levelpermissions: {}— Only file in the PR without it. Functionally safe (job-level grant still applies), but breaks the defense-in-depth consistency with the other 9 workflow files.
Both already flagged by yujiawei — concur fully.
Verdict
APPROVED. Clean governance wiring, correct permissions model, proper security annotations on dangerous triggers.
Add the standard org governance workflow suite to align with other Mininglamp-OSS repositories.
Files Added
auto-add-to-project.ymlcodeql.ymlissue-welcome.ymllabeler.ymlocto-ci-status.ymlocto-issue-feed.ymlocto-pr-feed.ymlpr-contributor-welcome.ymlrelease-drafter.ymlrelease-publish.ymlstale.ymlworkflow-sanity.ymlAll workflows call centralized reusable workflows from
Mininglamp-OSS/.github.Part of org CI/CD governance hardening (Phase 3).