Repository navigation
Security and Code Scanning
This page covers how SentinelGo's code is scanned, how findings get triaged and fixed, and how changes reach main. Read it before changing a workflow file, suppressing a finding, or merging a PR.
All findings land in Security → Code scanning.
| Scanner | Where | Trigger | Blocks merge? |
|---|---|---|---|
| CodeQL (Go + Actions) | codeql.yml |
push/PR to main, weekly (Mon 02:00 UTC) |
Yes, via the code_scanning ruleset rule |
| gosec |
ci.yml → Security Scan
|
push/PR to main
|
No. It's insight only and uploads SARIF |
| govulncheck |
ci.yml → Security Scan
|
push/PR to main
|
Yes, fails the job |
| Trivy |
ci.yml → Security Scan
|
push/PR to main
|
Yes, fails the job |
| OpenSSF Scorecard | scorecard.yml |
push to main, weekly (Sat), branch-protection changes |
No. Feeds the README badge |
| SonarCloud | external app + ci.yml → SonarQube
|
push/PR to main
|
No (not a required check), but keep the quality gate green |
| Semgrep, GitGuardian | external apps | PRs | Yes. Both are required checks |
| Snyk | external app | PRs | No |
Build (darwin/amd64), Build (darwin/arm64), Build (linux/amd64), Build (windows/amd64), Test (ubuntu-latest), Test (macos-latest), Test (windows-latest), GitGuardian Security Checks, semgrep-cloud-platform/scan.
The ruleset uses a strict policy: a PR branch must be up to date with main before it can merge.
- Commit work on
dev.devis protected only against deletion and creation, so pushing directly is fine. - Open a
dev → mainPR. - Enable auto-merge right away. Don't merge by hand:
gh pr create --base main --head dev --title "..." --body-file pr.md gh pr merge <PR#> --auto --merge # merge commits only; squash/rebase are disabled
- GitHub merges the PR once every required check passes.
devsurvives the merge because the ruleset protects it from deletion. - Before the next PR, bring
devup to date:git fetch && git merge origin/main.
Dependabot opens PRs straight against main for Go modules and GitHub Actions (weekly, Monday). The strict up-to-date rule means every merge to main puts the other open PRs behind. Handle them one at a time:
- Enable auto-merge on each:
gh pr merge <PR#> --auto --merge. - Comment
@dependabot rebaseon one PR and wait for it to merge. - Repeat for the next. A PR can briefly show
DIRTY(conflict) right after the rebase request. That's normal; give Dependabot a minute to rebase it.
Treat each alert as one of three cases:
- Real defect: fix it. Add a test that reproduces it. Close the alert by fixing the code, not by dismissing it.
- False positive: annotate it inline, with a reason (see below), so the reasoning lives next to the code.
-
Process or repo-setting check (e.g. Scorecard
BranchProtection,CodeReview,CIIBestPractices): dismiss it in the UI as won't fix, with a justification comment.
For larger work, open a GitHub issue per alert group, with the triage reasoning in the body. See #67–#70 for examples.
Put a #nosec comment on the line above the flagged statement, naming the rule and giving a reason:
// #nosec G304 - path is an entry returned by os.ReadDir(efivarsDir)
data, rerr := os.ReadFile(filepath.Join(efivarsDir, e.Name()))-
//nolint:gosecdoes not work for the SARIF scan. golangci-lint honours it, but the standalone gosec in CI ignores it. Use#nosec. - Always name the rule (
G304,G302 G304, …). A bare#nosechides future, unrelated findings on the same line. -
scripts/(release/CI tooling that takes paths from argv) is excluded from the gosec scan via-exclude-dir=scripts. It is never shipped in the agent binary.
gosec analyses the build for one OS at a time. CI runs on Linux, so run it on Linux to reproduce the CI results:
GOOS=linux gosec -exclude-dir=scripts ./...
GOOS=darwin gosec -exclude-dir=scripts ./... # for _darwin.go filesRunning it on a Windows machine without GOOS set scans the Windows build and reports a different set of findings.
These rules close the Scorecard PinnedDependencies and TokenPermissions checks. Apply them to every new or edited workflow.
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0A tag like @v7 or @v0.36.0 can be moved to point at different code, and the release job holds the signing key. Keep the # vX.Y.Z comment: Dependabot's github-actions config uses it to propose updates that bump the SHA and the comment together.
To resolve a tag to a SHA:
git ls-remote --tags https://github.com/<owner>/<action>.git | grep 'refs/tags/v7.0.0'
# For annotated tags, use the line ending in ^{} (the commit, not the tag object).- Top level of every workflow:
permissions: contents: read(Scorecard usesread-all). - Grant write scopes only at job level, and only on the jobs that need them:
-
release.yml→releasejob:contents: write -
codeql.yml→analyzejob:security-events: write -
ci.yml→ Security Scan job:security-events: write(SARIF upload)
-
-
release-trigger.ymlpushes its tag with theRELEASE_PATsecret (persisted byactions/checkout), so itsGITHUB_TOKENstays read-only. The push has to use a PAT: tags pushed withGITHUB_TOKENdon't triggerrelease.yml.
.gitignore covers SQLite stores (sentinelgo_*.db, tasks.sqlite), coverage profiles (*.out) and stray /dev/ output. Watch for:
-
go build -o /dev/nullon Windows creates a real file at./dev/null. Usego vetorgo build -o NULinstead. - Before committing, run
git statusand check for unexpected binaries.
| Area | State |
|---|---|
| gosec | All alerts fixed or annotated (#70, #73) |
Scorecard PinnedDependencies / TokenPermissions / BinaryArtifacts
|
Fixed in #71 |
Scorecard Fuzzing
|
Planned: Go native fuzzing of parsers that take untrusted input, see #72 |
Scorecard BranchProtection, CodeReview
|
Accepted. The maintainer can bypass the main ruleset for small direct merges |
Scorecard CIIBestPractices
|
Not pursued (requires registering for the OpenSSF Best Practices badge) |
SentinelGo
Repository docs