Skip to content

chore(cla): call the shared CLA reusable instead of a self-hosted job (ENG-2017) - #222

Merged
mindsdb-devops merged 4 commits into
mainfrom
chore/eng-2017-cla-off-self-hosted-runner
Aug 28, 2026
Merged

chore(cla): call the shared CLA reusable instead of a self-hosted job (ENG-2017)#222
mindsdb-devops merged 4 commits into
mainfrom
chore/eng-2017-cla-off-self-hosted-runner

Conversation

@lucas-koontz

@lucas-koontz lucas-koontz commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

User story

As a maintainer of this repository
I want the CLA check to run on a disposable GitHub-hosted runner
So that a stranger opening a pull request cannot start a pod inside our clusters

Why this matters

cla.yml ran on mdb-dev, which is not a GitHub VM. It is a pod inside our newdev
EKS cluster, holding a Kubernetes identity, an AWS role and a filesystem other
repositories' credentialed jobs write into.

This workflow triggers on pull_request_target and issue_comment. Both run in
base-repo context, so GitHub's fork-approval gate never applies: the run starts
when a pull request opens or a comment is posted, from any account, with nobody
clicking anything. Outside accounts have already done it here.

The job also ran contributor-assistant/github-action@v2.6.1, a mutable tag, so
whoever controls that tag upstream chose what ran on the pod.

What happens today

flowchart TD
    S["Any GitHub account"] --> E["Opens a PR, or comments on any issue"]
    E --> N["Base-repo trigger, so no approval gate applies"]
    N --> J["Job claims a pod on mdb-dev"]
    J --> P["Four write scopes on GITHUB_TOKEN"]
    J --> A["Third-party action on a mutable tag"]
Loading

What should happen

flowchart TD
    S["Any GitHub account"] --> E["Opens a PR, or comments on any issue"]
    E --> G{"Job condition: a PR event, or a CLA comment?"}
    G -->|"no, an unrelated comment"| SKIP["Job skipped, no runner claimed"]
    G -->|"yes"| J["Job runs on ubuntu-latest"]
    J --> A["Action pinned to a commit SHA"]
Loading

Acceptance criteria

  • The CLA job no longer requests mdb-dev.
  • An issue_comment that is not a CLA comment leaves the job skipped, with no runner claimed.
  • A pull request still gets the check, so an unsigned author is asked to sign.
  • Negative: the existing signature ledger is untouched and still readable.

How to test

  1. Open a pull request from a fork using an account that is not in the allowlist. The CLA job runs on a GitHub-hosted runner and the bot comments asking for a signature.
  2. Comment the signature phrase. The re-check passes and the signature lands on the cla branch.
  3. Comment something unrelated on any open issue. The CLA workflow shows the job as skipped and claims no runner.

Notes for the reviewer

The allowlist is gone from this file, and staff now sign like everybody else. Fifteen repositories carried six different hand-maintained copies naming 25 people between them, and 11 of those 25 had already left the org while still being exempt from signing. It now defaults in the reusable and is bots only: dependabot[bot] and mindsdb-release-train[bot], the two that actually open pull requests in this org. A bot cannot post the agreement sentence, so without an exemption its pull request is red forever.

Dropping the line also drops two live defects that rode inside it. bot* compiled to an unanchored new RegExp("bot.*").test(login), so it exempted any login containing "bot", including robotnik and sabotage; anyone could opt out of the CLA by choosing a username. And Stpmax never matched the real login StpMax, because non-wildcard entries use a case-sensitive ===. Needs mindsdb/github-actions#56, which gives the input its default.

.github/ gets a code owner. This repo had no CODEOWNERS, so a change to what runs in CI, on which runner, and with which secrets in scope needed no particular reviewer, on a repo that accepts outside pull requests. Auto-request only for now: a hard gate needs require_code_owner_reviews in branch protection, which this repo does not set and which rides ENG-2013's org ruleset. Faking it here would be a file that looks like a control and is not one.

The green CLAssistant row on this pull request does not exercise this change. pull_request_target loads the workflow from the base branch, so the check that passed here is the copy this PR replaces, running on mdb-dev. The new job cannot test itself on its own pull request; it is exercised on the first pull request opened after this merges.

The on: and permissions: blocks swap places, which is why the diff looks bigger than it is. Every converted wrapper now reads name, permissions, triggers, job, in that order. No trigger and no scope changes as a result of the move itself.

This replaces a hand-rolled job with the reusable anton, cowork and cowork-server already call. Nothing new was invented. The reusable is hardened in the same change set at mindsdb/github-actions, which pins the action to a commit, moves the event filter from the step to the job, drops its runs-on input entirely, and reduces actions: write to actions: read.

The actions scope is read, not write, and that is deliberate. The upstream README asks for write. The only write it buys is pullRerunRunner.ts re-running a previously failed CLA run, and that API refuses a GITHUB_TOKEN, so the call already failed and was swallowed. Dropping the scope altogether does break the job, because the same file lists the repository's workflows first and main.ts turns any throw into a failure.

The signature ledger is untouched. path-to-signatures and branch still resolve to the same file on the same branch, so every existing signature stays where it is.

The agreement link names the canonical repository rather than a redirect. Every URL the org used for this document was a rename redirect. They all resolve to the same file and serve byte-identical content, so nothing changes for a reader today. A redirect stops being harmless the moment somebody creates a repository at the old name, and this is the page a contributor reads before agreeing to it.

Verified locally

Check What I observed
actionlint on the changed file Clean, v1.7.12. This repo runs no workflow linter of its own, so I ran the version the org's shared lint workflow pins.
The reusable's runner default Read from mindsdb/github-actions@main: runs-on: ubuntu-latest, and after this change set the input does not exist at all.
Nothing else reads the removed input gh search code over the org: anton, cowork and cowork-server call the reusable and none of them passes runs-on.
The existing ledger Still resolves on the cla branch, 2 signers, unchanged by this PR.

Ships with

One behaviour across eleven repositories, one pull request each. The anchor is
mindsdb/github-actions, which hardens the shared reusable this file now calls.
There is no Deploys: line and no pull request environment: these are library
repositories with no deploy pipeline, so nothing here brings up an environment.

Merge order: the anchor first, and that is a requirement rather than a
preference.
This wrapper grants actions: read, and until
mindsdb/github-actions#55 merges the reusable still declares actions: write.
A called workflow's permissions are enforced when its file is loaded, so a
callee naming a scope its caller has not granted rejects the whole run as a
startup_failure with zero jobs, and there is no job left to report it. The
run is red, the CLA gate is down, and nothing announces either.

Refs: ENG-2017

… (ENG-2017)

The CLA check ran on mdb-dev, a pod inside the newdev cluster. Its triggers,
pull_request_target and issue_comment, both run in base-repo context, so
GitHub's fork-approval gate never applied and any account could start that pod
by opening a pull request or leaving a comment.

Replace the hand-rolled job with the reusable anton, cowork and cowork-server
already call. It runs on ubuntu-latest, pins the third-party action to a commit,
grants actions read rather than write, and skips the job outright for a comment
that is not a CLA comment.

Refs: ENG-2017
@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
mindsdb_sdk
   agents.py1794774%29, 101, 104, 107, 110, 118, 126, 146, 167, 178, 181, 185, 187, 189, 191, 193, 195, 197, 261, 274, 285, 296, 299–303, 318, 327–331, 375, 383–384, 442, 450–451, 455, 486–488, 490–491, 518–519, 521
   databases.py58788%85–86, 149, 177, 188–194
   handlers.py37197%77
   jobs.py97793%40, 52, 80, 84, 146–149
   knowledge_bases.py1301886%70–73, 132–136, 160, 189, 196, 200–202, 206, 228–232, 242
   ml_engines.py42393%94, 126, 128
   models.py2111991%109, 140–141, 222, 231, 233, 303, 339, 349, 373, 398, 492, 500, 519, 535, 543, 568, 572, 585
   projects.py61198%158
   query.py13192%14
   server.py31294%86–87
   tables.py1301588%140–142, 145, 165, 192, 203–204, 209, 224, 227, 321, 342–347, 356, 376
   tree.py321650%18–19, 24–28, 41–57
   views.py37295%105, 138
mindsdb_sdk/connectors
   rest_api.py2405677%19–29, 35–36, 51, 55, 58–59, 79–81, 87–89, 108, 111, 118–121, 144, 158–166, 187–188, 223–226, 240–241, 295–300, 304–316
mindsdb_sdk/utils
   agents.py50492%72, 79–81
   mind.py47470%1–128
   openai.py853065%37–40, 83–85, 107, 148–158, 215–216, 234–240, 258–276
   table_schema.py21210%1–54
TOTAL158229781% 

Tests Skipped Failures Errors Time
26 0 💤 0 ❌ 0 🔥 6.784s ⏱️

…017)

Both URLs the org uses for this document are rename redirects that resolve to
the same repository and serve byte-identical content. A redirect is fine until
somebody creates a repository at the old name, and this is the page a
contributor reads before agreeing to it. Name the repository that actually
holds the file.

Refs: ENG-2017
@lucas-koontz lucas-koontz self-assigned this Aug 27, 2026
…2017)

The allowlist moved into mindsdb/github-actions and is bots only. This repo
carried one of six hand-maintained copies naming people, and 11 of the 25 names
across those copies had already left the org while still being exempt from
signing. Staff sign like everybody else now. A bot cannot sign, so the two that
actually open pull requests in this org stay exempt in the reusable.

Dropping the line also drops two defects that rode inside it. `bot*` compiled to
an unanchored `new RegExp("bot.*").test(login)`, so it exempted any login
containing "bot", `robotnik` and `sabotage` included. And `Stpmax` never matched
the real login `StpMax`, because non-wildcard entries are compared with a
case-sensitive `===`.

Needs mindsdb/github-actions#56 first, which gives the input a default.
This repo accepts pull requests from outside contributors and had no CODEOWNERS
at all, so a workflow change here needed no particular reviewer. Everything
under .github/ decides what runs in CI, on which runner, and with which secrets
in scope, which is a trust boundary rather than product code.

Auto-request only for now. Making it a hard gate needs require_code_owner_reviews
in branch protection, which this repo does not have; that rides ENG-2013's org
ruleset.
@github-project-automation github-project-automation Bot moved this from to review to approved in Tracking PRs Aug 28, 2026
@mindsdb-devops
mindsdb-devops merged commit 77584ec into main Aug 28, 2026
6 checks passed
@mindsdb-devops
mindsdb-devops deleted the chore/eng-2017-cla-off-self-hosted-runner branch August 28, 2026 00:34
@github-project-automation github-project-automation Bot moved this from approved to merged in Tracking PRs Aug 28, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

Status: merged

Development

Successfully merging this pull request may close these issues.

3 participants