Skip to content

fix(ci): make the linters and secret scanning actually able to fail - #756

Merged
CybotTM merged 5 commits into
mainfrom
fix/sharpen-gates
Jul 28, 2026
Merged

fix(ci): make the linters and secret scanning actually able to fail#756
CybotTM merged 5 commits into
mainfrom
fix/sharpen-gates

Conversation

@CybotTM

@CybotTM CybotTM commented Jul 28, 2026

Copy link
Copy Markdown
Member

An audit of this repo's quality gates found several that were configured but inert — the same pattern as the documentation rule that sat disabled: true for years. This sharpens the repo-local ones and fixes what they immediately surfaced.

Secret scanning found nothing because it had no rules

A gitleaks config file replaces the built-in ruleset unless it extends it. .gitleaks.toml declared only an [allowlist] — so there were zero detection rules and every scan reported "no leaks found" regardless of input.

Proven by A/B on the same file:

Result
config as committed no leaks found
identical config + [extend] useDefault = true leaks found: 1

Turning it on immediately flagged four doc examples. The JWT ones are truncated placeholders. docs/webhooks.md and middlewares/presets/ntfy-token.yaml carried tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 — indistinguishable in shape from a real ntfy access token. All are now unmistakable placeholders.

⚠️ If that value was ever a real token it has been in public git history since 2025-12 and needs rotating. Replacing the file does not undo that. Only someone with access to the ntfy instance can say.

The blanket staticcheck exclusions were hiding a real defect

text: "QF" is an unanchored regex over the message, so it dropped every QF#### check. Alongside it, text: "ST1018:" was suppressing a finding about invisible Unicode — and it was right: the HTML mail body template contained five U+200B zero-width spaces, shipped in every notification mail this daemon sends. Zero-width characters are a well-known spam-filter signal.

Job ⟦ZWSP⟧<b>{{.Job.GetName}}</b>,
Execution <b>{{status .Execution}}</b> in ⟦ZWSP⟧<b>{{.Execution.Duration}}</b>⟦ZWSP⟧,

Removed. staticcheck now selects checks explicitly (all minus QF1008, the one pure-style check that fires widely here) instead of filtering by message text.

Also

  • uniq-by-line: false — the default drops a second linter's finding whenever another linter already reported on that line.
  • Five error strings lowercased: ST1005 wants it, and this codebase already writes docker unavailable / creating docker client everywhere else. These five were the outliers.
  • Eleven mechanical staticcheck findings fixed (WriteString(fmt.Sprintf(…))fmt.Fprintf, De Morgan, inferrable types).

gosec annotations

netresearch/.github#312 makes gosec blocking. Its three findings here are false positives and are annotated with reasons rather than worked around:

  • both auth cookies do set HttpOnly and SameSite=Strict, and derive Secure from the request scheme on purpose — a hard true would silently break the common plain-HTTP-on-a-private-network deployment;
  • the third marshals a password because the Docker API requires exactly that payload in X-Registry-Auth.

Verification

golangci-lint 0 issues · gosec exit 0 · gitleaks clean · build and vet clean under the default, integration and e2e tags · go test -race ./... 14/14.

An audit of the quality gates found several that were configured but inert.
This sharpens the repo-local ones and fixes what they immediately surfaced.

Secret scanning found nothing because it had no rules. A gitleaks config
file REPLACES the built-in ruleset unless it extends it, and .gitleaks.toml
declared only an allowlist. Verified: the same file with [extend]
useDefault = true reports a planted Slack token, without it reports "no
leaks found". Every secret pattern was invisible to CI.

Turning it on flagged four doc examples. The JWT ones were truncated
placeholders; docs/webhooks.md and middlewares/presets/ntfy-token.yaml
carried a token-shaped ntfy value that is indistinguishable from a real
one. All are now unmistakable placeholders. If that value was ever real it
has been in public history since 2025-12 and needs rotating — replacing the
file does not undo that.

The blanket staticcheck exclusions hid a real defect. `text: "QF"` matched
every QF check by message text, and the ST1018 exclusion was suppressing a
finding about invisible Unicode: the HTML mail template contained five
U+200B zero-width spaces, shipped in every notification mail, which is a
known spam-filter signal. Removed, along with the exclusions; staticcheck
now selects checks explicitly with QF1008 as the one documented exception.

Also: uniq-by-line disabled, so a second linter's finding on a line another
linter already reported is no longer dropped; five error strings lowercased
to match both ST1005 and this codebase's own convention; eleven mechanical
staticcheck findings fixed.

gosec is about to become blocking in the shared workflow. Its three
findings here are false positives and are annotated rather than worked
around: both auth cookies set HttpOnly and SameSite=Strict and derive
Secure from the request scheme deliberately, since the UI is commonly
served over plain HTTP on a private network; the third marshals a password
because the Docker API requires exactly that payload.

Verified: golangci-lint 0 issues, gosec exit 0, gitleaks clean, build and
vet clean under the default, integration and e2e tags, go test -race 14/14.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI review requested due to automatic review settings July 28, 2026 07:16
@github-actions

Copy link
Copy Markdown

Dependency Review

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

Scanned Files

None

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 28, 2026
Comment thread docs/API.md Fixed
Comment thread docs/API.md Fixed
github-actions[bot]
github-actions Bot previously approved these changes Jul 28, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown

⚠️ Mutation Testing Results

Mutation Score: 0.00% (threshold: 60%)

⚠️ Score is below threshold. Consider improving test coverage or test quality.

What is mutation testing?

Mutation testing measures test quality by introducing small changes (mutations) to the code and checking if tests detect them. A higher score means better test effectiveness.

  • Killed mutants: Tests caught the mutation (good!)
  • Survived mutants: Tests missed the mutation (needs improvement)

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.88889% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.64%. Comparing base (71575aa) to head (03e507b).

Files with missing lines Patch % Lines
cli/init.go 0.00% 1 Missing ⚠️
config/sanitizer.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #756      +/-   ##
==========================================
- Coverage   87.65%   87.64%   -0.01%     
==========================================
  Files          90       90              
  Lines       12058    12054       -4     
==========================================
- Hits        10569    10565       -4     
  Misses       1198     1198              
  Partials      291      291              
Flag Coverage Δ
integration 87.64% <88.88%> (-0.01%) ⬇️
unittests 85.19% <88.88%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Repairing the gitleaks ruleset made CI red, correctly: gitleaks scans every
commit, not just the working tree, so correcting the files does not remove
what was committed. Five findings remain reachable in history.

Each was reviewed. Two are the ntfy placeholder from 2025-12, two are a
truncated JWT header used as an Authorization example, one is a curl auth
header in the security docs. None is a live credential; if one had been,
the answer would be rotation rather than an ignore entry, since a rewrite
of public history is not a remedy anyone can rely on.

Verified that this silences only those five: a freshly planted Slack token
is still reported (leaks found: 1) with the ignore file in place, and the
tree is clean again once it is removed.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Jul 28, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

The previous commit rewrote .gitleaksignore instead of appending to it,
dropping the test-file and test-constant entries that were already there.
Restored verbatim.

While restoring: those entries are bare paths and substrings, which is not
the .gitleaksignore format — it matches finding fingerprints of the form
commit:file:rule:line — so they suppress nothing. The suppression that
actually works for those files lives in .gitleaks.toml's allowlist. Left in
place and annotated rather than removed, since deleting them is a separate
decision.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Jul 28, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

golangci-lint analysed nothing behind a build tag: run.build-tags was unset,
so the entire e2e suite and the Docker integration adapters — 18 files — were
outside every linter. The config even carried exclusion rules written for
those paths (path: integration_test\.go, path: e2e/.*_test\.go) that could
never match, which is how long this went unnoticed.

Enabling the tags exposed two findings, both fixed rather than suppressed:
client.NewClientWithOpts in the benchmark is deprecated in favour of
client.New, and the copyright header in core/integration_test_main.go abutted
the package clause so it was being read as the package doc comment.

It also exposed a latent platform problem. e2e/helpers_test.go uses
syscall.Setpgid, Getpgid and Kill, which do not exist on Windows, but the
suite was tagged e2e without unix — it had simply never been type-checked
for that platform. Tagging only that file breaks the package, since it
provides the helpers the other e2e files call, so the whole suite is now
e2e && unix. It is unix-only in substance: it drives process groups and
signals.

Verified on both platforms, which the earlier verification did not do:
GOOS=linux and GOOS=windows both report 0 issues. The suite still runs — 13
e2e tests found and passing — and build/vet are clean under the default,
integration and e2e tags.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

github-actions[bot]
github-actions Bot previously approved these changes Jul 28, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

QUICK_REFERENCE.md told operators to add max-runtime to a [job-exec]
section. The key exists on RunJob, RunServiceJob and [global], but ExecJob
has no such field, so the documented configuration is rejected.

Point at the global default instead, and mark the block as ini rather than
bash so a config-parsing check can see it — the snippet was invisible to
the docs gate precisely because of the fence language.

Found by the documentation-drift gate being built for this repo, which is
the kind of defect it exists to catch.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
@sonarqubecloud

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated approval for maintainer PR

All automated quality gates passed. See SECURITY_CONTROLS.md for compensating controls.

@CybotTM
CybotTM added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 04acb22 Jul 28, 2026
27 checks passed
@CybotTM
CybotTM deleted the fix/sharpen-gates branch July 28, 2026 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants