Skip to content

feat(ci): harden pre-merge workflows for dev gate#55

Merged
Astro-Han merged 6 commits into
devfrom
worktree-feat-ci-merge-gate
Apr 20, 2026
Merged

feat(ci): harden pre-merge workflows for dev gate#55
Astro-Han merged 6 commits into
devfrom
worktree-feat-ci-merge-gate

Conversation

@Astro-Han

Copy link
Copy Markdown
Owner

Summary

Hardens the four PR-gating workflows and their supporting config so dev can be made a real merge gate in a follow-up (non-PR) step. Closes the "branch protection is empty" gap from #54 on the code side; the ruleset flip is a repo setting applied via gh api after this PR merges and is intentionally not part of the PR.

Refs #54.

Changes

Five commits, each a reversible milestone:

  1. d259de8e4 — SHA-pin first-party actions across PR-gating workflows. Aligns ci.yml, desktop-smoke.yml, e2e-artifacts.yml with the SHA-pinning already used in codeql.yml and build.yml. No behaviour change; supply-chain hygiene only.

  2. 68d984a72 — Add dependency-review-action workflow, non-blocking. New single-purpose workflow (dependency-review.yml) following the CodeQL pattern. Uses the action's own warn-only: true (not a job-level continue-on-error) so action-level failures still surface while policy findings only warn. Fork-PR guard mirrors the junit-publisher in ci.yml. Stays non-blocking until catalog:/workspace parsing is verified on a real PR run; then drop warn-only, set fail-on-severity: high, and add to the ruleset.

  3. d6c209023 — Expand Dependabot to bun ecosystem with grouping. Uses package-ecosystem: "bun" (Dependabot >= v1.2.5) rather than "npm" so bun.lock and catalog: are parsed by the correct updater. Named groups (electron / typescript-tooling / turbo-build / testing / opencode) plus catch-all minor-patch groups keep transitive churn bundled. open-pull-requests-limit: 5 per ecosystem.

  4. 952c13f12 — Remove dead husky wiring. .husky/ had no user-level hooks, the formatter hook was removed previously, and "prepare": "husky" was running a no-op on every install. Drop both the script and the devDependency.

  5. f7b63632e — Guard comments for ruleset + check-aggregator drift.

    • codeql.yml: required merge check on dev; ruleset entry name is codeql / analyze-js-ts. Decision recorded in [Feature] Harden CI as a real merge gate for dev #54 (D1).
    • ci.yml, desktop-smoke.yml: every new job must be listed in check.needs or its failure will silently not block merge. Threshold for switching to alls-green flagged.
    • e2e-artifacts.yml: continue-on-error: true means this workflow must never be set as a required check.

What is intentionally NOT in this PR

  • The ruleset itself. Branch protection is a GitHub repo setting applied via gh api or web UI, not a file in a PR. It must be flipped on after this PR merges, so the new checks can prove green on this PR's own runs first.
  • bun turbo lint CI job. Repo has no lint infrastructure today (no package defines a "lint" script, turbo.json has no lint task). Adding the CI job requires picking a linter and configuring each package first; that is a separate track.
  • alls-green aggregator. Deferred per [Feature] Harden CI as a real merge gate for dev #54; guard comments in ci.yml/desktop-smoke.yml flag the threshold for revisiting.

Review trail

Two rounds of /crosscheck review (Claude Opus + Codex) ran against earlier commits on this branch. Findings are folded into the final 5 commits (not kept as separate "review fix" commits), and the decisions are written into the issue body under D1-D5 so future readers have context. Summary of what the reviewers caught and how it was addressed:

  • Round 1: package-ecosystem must be "bun" not "npm" for Bun projects (P1, fixed in commit 3). Job-level continue-on-error would hide action-level failures; use step-level warn-only instead (P2, fixed in commit 2).
  • Round 2: Fork PRs get a read-only GITHUB_TOKEN, so comment-summary-in-pr writes fail or silently no-op; add the if: guard mirroring ci.yml (P2, fixed in commit 2). Guard comment in codeql.yml did not spell out the ruleset entry name (P2, fixed in commit 5). Catch-all Dependabot groups benefit from explicit patterns: ["*"] for readability (P3, fixed in commit 3).

Findings deliberately not addressed in this PR (captured as follow-ups below).

Follow-ups

  • Flip the ruleset (non-PR): add ci / check, desktop-smoke / check, codeql / analyze-js-ts as required status checks on dev; enable "require conversation resolution" and "require branches to be up-to-date." Do NOT enable "require linear history" (conflicts with the merge-commit-for-own-PRs convention; [Feature] Harden CI as a real merge gate for dev #54 D2).
  • Verify bun dependency graph on this PR's first run: does dependency-review-action actually see the monorepo's deps? If yes, drop warn-only, set fail-on-severity: high, add to ruleset.
  • Stand up lint infrastructure (separate issue): pick tool, wire per package, add turbo lint task, add CI job.
  • Fix docs-only glob gap (pre-existing): is_docs_path() in ci.yml/desktop-smoke.yml uses packages/*/README.md which doesn't match the nested workspace packages/sdk/js/README.md. Surfaced by crosscheck but pre-dates this PR.
  • Add alls-green aggregator when needs: list grows past ~5 entries.
  • PR/issue title lint enforcing [Feature]/[Bug] prefix; commit-message Conventional-Commits lint ([Feature] Harden CI as a real merge gate for dev #54 P3).

Test plan

  • On this PR, ci / check passes green
  • desktop-smoke / check passes green
  • codeql / analyze-js-ts completes successfully
  • dependency-review / review runs and either posts a summary comment or clearly shows why not (fork guard only disables it on forks, which this PR is not)
  • e2e-artifacts uploads artifacts (non-blocking as designed)
  • Inspect dependency-review / review output to confirm GitHub's dep graph parses bun.lock and workspaces; decide whether to drop warn-only in a follow-up

Align ci.yml, desktop-smoke.yml, and e2e-artifacts.yml with the SHA pinning
already used in codeql.yml and build.yml. Official GitHub actions previously
referenced by version tag (actions/checkout@v6, setup-node@v6.3.0, cache@v5,
upload-artifact@v7) now pin to the resolved commit SHA with a trailing
readable comment.

Refs #54
Separate workflow following the codeql.yml pattern: single-purpose
PR-scoped supply-chain scan. Complements CodeQL (which scans source
code) by inspecting the dependency graph for CVEs and license issues.

Non-blocking during the initial rollout via the action's own
`warn-only: true` input rather than a job-level continue-on-error, so
action-level failures (auth, parser, network) still surface while
policy findings (high-severity CVEs, license violations) only warn.
Fork-PR guard mirrors the junit-publisher pattern in ci.yml: on fork
PRs, GITHUB_TOKEN is read-only and the comment-summary-in-pr write
would silently no-op under warn-only.

GitHub's dependency graph supports bun.lock directly; the open question
is whether the `catalog:` field and workspace resolution are parsed
well enough to surface actionable findings. Once the first PR runs
confirm that, drop warn-only, set fail-on-severity: high, and add this
job to the dev ruleset.

Refs #54
Adds weekly bun-ecosystem updates (Dependabot >= v1.2.5) so bun.lock
and Bun-specific manifest features (the catalog: field and workspaces)
are parsed by the correct updater. Named groups (electron,
typescript-tooling, turbo-build, testing, opencode) keep transitive
churn bundled so the PR queue stays reviewable; remaining production
and development updates fall into catch-all minor-patch groups with
explicit patterns: ["*"] for readability.

open-pull-requests-limit capped at 5 to protect the PR gate's
credibility during the first few weeks.

Refs #54
Husky was installed via the "prepare" script but no user-level hooks
(.husky/pre-commit etc.) existed; the formatter hook that used to live
there was removed previously and nothing replaced it. Drop both the
script and the devDependency so postinstall stops running a no-op.

If a real pre-commit check is needed later, wire it up explicitly
rather than reviving this ghost.

Refs #54
- codeql.yml: document that this workflow is a required merge check on
  dev (ruleset entry: `codeql / analyze-js-ts`), and that the
  "separate file" pattern is intentional, not a claim that the gate
  is optional. Decision recorded in issue #54 (D1).
- ci.yml, desktop-smoke.yml: warn future editors that new jobs must be
  added to check.needs, otherwise their failures silently do not block
  merge. Flag the threshold for switching to alls-green.
- e2e-artifacts.yml: document that continue-on-error: true means this
  workflow must never be set as a required check; otherwise it would
  report success forever regardless of test outcome.

Refs #54
@Astro-Han Astro-Han added enhancement New feature or request ci Continuous integration / GitHub Actions P0 Blocking / highest priority labels Apr 20, 2026
@github-actions

github-actions Bot commented Apr 20, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/cache 27d5ce7f107fe9357f9df03efb73ab90386fccae 🟢 6.3
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Maintained🟢 1030 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Binary-Artifacts🟢 10no binaries found in the repo
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/checkout de0fac2e4500dabe0009e67214ff5f5447ce83dd 🟢 5.7
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 10all changesets reviewed
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Packaging⚠️ -1packaging workflow not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Security-Policy🟢 9security policy file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
SAST🟢 8SAST tool detected but not run on all commits
actions/actions/setup-node 53b83947a5a98c8d113130e565377fae1a50d02f 🟢 5.9
Details
CheckScoreReason
Maintained🟢 810 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 8
Code-Review🟢 10all changesets reviewed
Binary-Artifacts🟢 9binaries present in source code
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 1branch protection is not maximal on development and all release branches
SAST🟢 9SAST tool is not run on all commits -- score normalized to 9
actions/actions/upload-artifact 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a 🟢 6
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Maintained🟢 88 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 8
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 10all changesets reviewed
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits

Scanned Files

  • .github/workflows/e2e-artifacts.yml
  • package.json

The SHA-pin commit (d259de8) changed actions/checkout@v6 to
actions/checkout@de0fac... and actions/upload-artifact@v7 to
actions/upload-artifact@043fb46... in the PR-gating workflows. The
self-referential workflow tests under packages/opencode/test/github/
and packages/opencode/test/config/ assert the exact `uses:` values,
so they needed the same update.

No logic change; only the expected SHA values are touched.

Refs #54
@Astro-Han Astro-Han merged commit 6b019e1 into dev Apr 20, 2026
14 of 16 checks passed
@Astro-Han Astro-Han deleted the worktree-feat-ci-merge-gate branch April 20, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continuous integration / GitHub Actions enhancement New feature or request P0 Blocking / highest priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant