Skip to content

feat: code scanning with CodeQL, and secret scanning as a setting - #65

Merged
vannt-dev merged 3 commits into
mainfrom
feat/security-module
Oct 13, 2026
Merged

vannt-dev merged 3 commits into
mainfrom
feat/security-module

Conversation

@vannt-dev

@vannt-dev vannt-dev commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

This branch was cut from fix/ship-update-workflow, so it contains #64 (both add a line to the same list in package.json). Merge #64 first; this one then has to be brought up to date with main so that its diff shows only its own commit.

What

Two things the README said repokeeper did not set up.

Code scanning: modules.security: true writes .github/workflows/security.yml:

jobs:
  codeql:
    uses: vannt-dev/repokeeper/.github/workflows/codeql.yml@v0
    permissions: { security-events: write, actions: read, contents: read }
    with:
      languages: '[{"language":"javascript-typescript","build-mode":"none"},{"language":"actions","build-mode":"none"}]'

It runs on every pull request, on every push to the default branch and once a week. The languages come from the stacks:

Stack CodeQL language Build
node javascript-typescript none
python python none
java java-kotlin none
kotlin java-kotlin autobuild
dotnet csharp none
go go autobuild
ruby ruby none
rust rust none
dart, php, script none: CodeQL does not know them

The workflow files are always analyzed too (actions). The identifiers and the build modes were checked against GitHub's documentation and the action's own action.yml, not written from memory: Java, C# and Rust are read from source, Kotlin and Go need a build.

Secret scanning: github.security.secret_scanning and secret_scanning_push_protection, read and set by repokeeper github apply like the Dependabot switches. When GitHub refuses (a private repository without Secret Protection), its answer is reported with what is missing.

Decisions to check

  1. No preset switches either on. Both are free on a public repository and paid on a private one. init --preset strict on a private repository would otherwise leave a workflow that fails on every push, and a github apply that stops at a 422. So security is a switch to ask for, like autoupdate, and init says once, when it writes the workflow, what a private repository needs. If strict should carry it anyway, it is a small change (the playground's strict has to follow, since a test compares them character for character).
  2. Secret scanning is a setting, not a workflow. GitHub's own scan needs no third-party tool to pin and keep current. A scan in CI (gitleaks, trufflehog), which would also work on a private repository without a paid plan, is not in this change.
  3. GitLab: nothing is written. GitLab's SAST and Secret Detection come in through include:, a list the project shares with repokeeper, and nothing here manages part of a list yet. check says so and names the templates. The same line feat: open a pull request when the standard has moved #62 drew for autoupdate.
  4. SECURITY_NEEDS_VERSION in the playground is 0.9.0, which is right if this is merged before 0.9.0 is released. If 0.9.0 goes out first, it has to say 0.10.0.

How

  • src/modules/security.ts, PlatformAdapter.codeScanning, CODEQL_LANGUAGES in platforms/github.ts (a line per stack, null for a stack CodeQL cannot analyze, so that a new stack has to say).
  • .github/workflows/codeql.yml: one job per language, init and analyze of github/codeql-action pinned by SHA at v4.38.3, input upload for callers that must not create alerts.
  • The caller is security.yml and the reusable workflow codeql.yml: two names, so that a repository that keeps its own copies (and this repository itself) can have both.
  • github/settings.ts: the two switches from security_and_analysis of the repository.
  • The standard version does not move: with the switch off, nothing generated changes.

Tested

  • Unit tests written first and seen failing: the module (test/modules-security.test.ts, 9), the settings (test/github-secret-scanning.test.ts, 6), the notes (test/report-security.test.ts, 3), the reusable workflow and its job in workflow-tests (test/workflows.test.ts). 457 tests in all, typecheck, lint, build, npm run standard.
  • The package itself: npm pack, the tarball installed in an empty project and run in two new repositories. One with node and go in a folder: security.yml calls vannt-dev/repokeeper/.github/workflows/codeql.yml@v0 with the three languages, and check then reports no drift. One with github.workflows.source: local: it also gets its own codeql.yml, read from the package.
  • A real run: workflow-tests now calls codeql.yml on JavaScript (read from source), Go (built by CodeQL, with go.mod in a folder) and the workflow files, with upload: never. See the codeql checks of this pull request.

Not tested

  • An upload of results into a repository's alerts: the workflow test runs with upload: never, so that the fixtures' findings do not become this repository's alerts. The upload is the action's own default behaviour.
  • The write of the two new switches against the real API. The read and the plan were run for real, as a dry run against the public vannt-dev/repokeeper-demo-go: with both switches asked for, github apply --dry-run answers that the settings match (GitHub reports both enabled there); with push protection asked off, it prints change security.secret_scanning_push_protection: true -> false and dry run: nothing applied, and the repository still has it on. The PATCH itself is covered by the tests' fake only; no repository's settings were changed.
  • The caller as generated, against @v0: the tag holds codeql.yml only after the next release.

modules.autoupdate with `github.workflows.source: local` gives the repository
its own copy of repokeeper-update.yml, read from the installed package. The
file was missing from the package's `files`, so that copy could not be read:
it worked from a checkout of this repository and would have failed from npm.

A test now checks that every reusable workflow a repository can be given a
copy of is covered by `files`.
repokeeper set up no scanning of any kind, and its README said so.

modules.security, off unless asked for, writes .github/workflows/security.yml.
Its codeql job calls the new reusable workflow codeql.yml on every pull
request, on every push to the default branch and once a week. The languages
come from the stacks: node, python, java, dotnet, ruby and rust are read from
source, go and kotlin are built by CodeQL itself, and the workflow files are
always analyzed too. Dart, PHP and scripts have no CodeQL language.

github.security takes secret_scanning and secret_scanning_push_protection,
which `repokeeper github apply` reads and sets like the Dependabot switches.
When GitHub refuses, its answer is reported with what a private repository
needs.

No preset switches either on: both are free on a public repository and paid
on a private one, where a preset would leave a failing workflow behind. On
GitLab the module writes nothing and says what does the work there.

workflow-tests runs codeql.yml on a language read from source and on one that
is built, without uploading the fixtures' findings.
@vannt-dev
vannt-dev merged commit bea1579 into main Oct 13, 2026
24 checks passed
@vannt-dev
vannt-dev deleted the feat/security-module branch October 13, 2026 14:56
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.

1 participant