Skip to content

chore(ci): add org governance workflow suite#9

Merged
lml2468 merged 18 commits into
mainfrom
chore/add-governance-workflows
May 21, 2026
Merged

chore(ci): add org governance workflow suite#9
lml2468 merged 18 commits into
mainfrom
chore/add-governance-workflows

Conversation

@lml2468
Copy link
Copy Markdown
Contributor

@lml2468 lml2468 commented May 21, 2026

Add the standard org governance workflow suite to align with other Mininglamp-OSS repositories.

Files Added

  • auto-add-to-project.yml
  • codeql.yml
  • issue-welcome.yml
  • labeler.yml
  • octo-ci-status.yml
  • octo-issue-feed.yml
  • octo-pr-feed.yml
  • pr-contributor-welcome.yml
  • release-drafter.yml
  • release-publish.yml
  • stale.yml
  • workflow-sanity.yml

All workflows call centralized reusable workflows from Mininglamp-OSS/.github.

Part of org CI/CD governance hardening (Phase 3).

@lml2468 lml2468 requested a review from a team as a code owner May 21, 2026 12:15
yujiawei
yujiawei previously approved these changes May 21, 2026
Copy link
Copy Markdown

@yujiawei yujiawei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_target triggers (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 run actions/checkout against the PR. The # zizmor: ignore[dangerous-triggers] annotations on labeler.yml and pr-contributor-welcome.yml are 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.yml correctly skips draft PRs with if: ${{ !github.event.pull_request.draft }}, which prevents leaking work-in-progress titles to the IM feed.
  • codeql.yml skips draft PRs (!github.event.pull_request.draft) and uses concurrency.cancel-in-progress: true only for PR runs, preserving main-branch and scheduled runs — correct.
  • octo-ci-status.yml listens on workflow_run filtered to main and completed; conclusion will always be set when the type is completed, so the reusable's required conclusion input is safe.

3. Findings

P0 / P1

None.

P2 / nits / maintainability (non-blocking)

  1. No .github/release-drafter.yml config in this repo. reusable-release-drafter.yml defaults to looking up release-drafter.yml under .github/. The release-drafter action 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.

  2. Coexistence of release.yml (existing) and release-publish.yml (new). The repo already has release.yml that runs goreleaser on tag push. The new release-publish.yml is workflow_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 in release-publish.yml) clarifying that goreleaser produces the binaries on tag push and release-publish.yml is the manual "promote draft → published" lever — otherwise future maintainers may delete one thinking it's redundant.

  3. Pinning reusable workflows to @main. Every caller pins Mininglamp-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 @v1 once the reusable suite stabilizes).

  4. stale.yml accepts 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.

  5. octo-pr-feed.yml passes feed_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 explicit feed_group_id line and let the default ride.

4. Additional observations

  • actions/checkout is 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 for pull_request_target. No change needed.
  • Schedules don't collide with each other or with existing CI: CodeQL 0 6 * * *, stale 0 3 * * *, and octo-ci-status is event-driven on workflow_run.
  • The if: github.event_name != 'pull_request' || !github.event.pull_request.draft guard in codeql.yml is the same pattern used in octo-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).
lml2468 added 3 commits May 21, 2026 20:34
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
yujiawei previously approved these changes May 21, 2026
Copy link
Copy Markdown

@yujiawei yujiawei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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@main

The 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

  1. Fix the description / scope mismatch in P2-1 (re-add codeql.yml + octo-ci-status.yml, or amend the body).
  2. After this lands, consider a small follow-up that pins all @main refs to a tag (P2-2) — easier to do once the new files are in than as part of this PR.
  3. Document the release.yml ↔ release-publish.yml split (P2-3) in CONTRIBUTING.md or as a comment in release-publish.yml.

4. Additional observations

  • Reusable workflow comments explicitly forbid adding actions/checkout to the pull_request_target reusables. None of the new callers violate this.
  • labeler.yml and pr-contributor-welcome.yml carry # zizmor: ignore[dangerous-triggers] with a one-line justification — good practice; matches the security-audit checklist.
  • octo-pr-feed.yml has if: ${{ !github.event.pull_request.draft }}, which correctly avoids noisy notifications during draft work.
  • The release-drafter config (.github/release-drafter.yml) change-template uses @$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.
Copy link
Copy Markdown

@yujiawei yujiawei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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@main

Suggest 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@main

This 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: write

Valid YAML and Actions accepts any key order, but the conventional ordering inside a job is usespermissionswithsecrets. Other files in this PR follow that ordering. Minor.

Things done well

  • pull_request_target is used only where required (labeler, contributor welcome, project add) and each instance has a zizmor: 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.yml correctly gates publish on a validate_run_id input, 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 including dependencies-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.

Copy link
Copy Markdown

@Jerry-Xin Jerry-Xin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_target callers (labeler, pr-contributor-welcome, auto-add-to-project) — confirmed none checkout PR code; metadata-only automation
  • pr-contributor-welcome.yml callee only uses issues.createComment() + issues.listComments()issues: write is sufficient (no PR-specific API unlike the labeler)
  • Security model: no actions/checkout in any sensitive workflow, idempotency markers present, concurrency groups correct

Non-blocking findings

  1. 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.yml is the most impactful gap (issue feed without PR feed = asymmetric notification coverage).

  2. issue-welcome.yml missing top-level permissions: {} — 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.

@lml2468 lml2468 merged commit 8c69e09 into main May 21, 2026
7 checks passed
@lml2468 lml2468 deleted the chore/add-governance-workflows branch May 21, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants