Skip to content

ci: security scanning suite and governance (consolidates #305-310)#1314

Merged
alteixeira20 merged 4 commits into
odysseus-dev:devfrom
nopoz:security/ci-bundle
Jun 11, 2026
Merged

ci: security scanning suite and governance (consolidates #305-310)#1314
alteixeira20 merged 4 commits into
odysseus-dev:devfrom
nopoz:security/ci-bundle

Conversation

@nopoz

@nopoz nopoz commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a security-scanning baseline as nine new files under .github/ and docs/, consolidating the six earlier per-scanner PRs (#305-310) into one reviewable change. Nothing existing is modified. Each scanner is its own workflow with a documented blocking-vs-advisory split, so the gate can be required incrementally rather than all at once. This is the security half of the CI baseline agreed in #2288.

Target branch

  • This PR targets dev, not main.

Linked Issue

Part of #2288

Type of Change

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change
  • Refactor / cleanup
  • Documentation only
  • CI / tooling / configuration

Checklist

How to Test

These are CI workflow files, so the scanners are the verification, not the app.

  1. The security workflows run on this PR. Confirm gitleaks, actionlint, zizmor, dependency-review, hadolint, and the advisory Trivy image scan pass.
  2. Locally, against the current dev tree, the suite's own five workflows are clean:
    • actionlint .github/workflows/{secret-scan,workflow-security,dependency-review,container-scan,container-trivy,codeql}.yml reports nothing.
    • zizmor --offline --min-severity=low on those files reports no findings.
    • hadolint --ignore DL3008 Dockerfile is clean (the suite ignores DL3008 on purpose; see below).
  3. docs/security-ci.md lists every check and the one-time settings (branch protection plus the Security-tab toggles) needed to enforce them after merge.

What is included

File Tool Blocks merge?
secret-scan.yml gitleaks, full history, pinned + checksum-verified Yes
workflow-security.yml actionlint + zizmor (audit the workflows themselves) Yes
dependency-review.yml PR dependency gate + advisory pip-audit Gate yes / pip-audit no
container-scan.yml hadolint Dockerfile lint Yes
container-trivy.yml Trivy image scan, table on PRs and SARIF only on main pushes Advisory
codeql.yml CodeQL for Python + JS, push + weekly Advisory

Plus .github/dependabot.yml (pip / npm / actions / docker), .github/CODEOWNERS, and docs/security-ci.md.

Notes:

  • All additive: nine new files, no existing file modified.
  • Actions pinned to commit SHAs; standalone binaries pinned and SHA-256 verified.
  • Tokens default-deny (permissions: {}), each job opts back into read-only.
  • Advisory scans (pip-audit, Trivy, CodeQL) never block; SARIF upload is gated to push so fork PRs don't fail on a read-only token.
  • DL3008 (unpinned apt versions) is intentionally ignored: a -slim base purges old package versions from Debian's repos, so pinning breaks future rebuilds. The base image is pinned instead and tracked by Dependabot.

Merging workflow files needs a token with workflow scope, or a merge through the web UI.

@pewdiepie-archdaemon

Copy link
Copy Markdown
Collaborator

The suite is thoughtfully structured, but I would not merge it in the current branch state.

First blocker: the branch is stale. The direct two-dot diff includes already-merged template/Cookbook/email/skills/vault/markdown files. Please rebase onto latest main so the direct diff only contains the intended additive governance/security files:

.github/CODEOWNERS
.github/dependabot.yml
.github/workflows/codeql.yml
.github/workflows/container-scan.yml
.github/workflows/dependency-review.yml
.github/workflows/secret-scan.yml
.github/workflows/workflow-security.yml
docs/security-ci.md

Second thing to coordinate: #1316 adds .github/workflows/pr-description-check.yml using actions/github-script@v7. This PR’s zizmor --offline --min-severity=low workflow-security gate will likely flag unpinned actions, so the two PRs should be made consistent before either is treated as final governance.

Also worth validating after rebase: run actionlint against the full workflow set and confirm hadolint does not block the existing Dockerfile. This PR adds blocking checks, so it should prove they are green against current main before branch protection depends on them.

PovilasKirna added a commit to PovilasKirna/odysseus that referenced this pull request Jun 2, 2026
Pins actions/github-script@v7 to its exact commit SHA as required by the
workflow-security gate in odysseus-dev#1314 (zizmor --offline --min-severity=low).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PovilasKirna added a commit to PovilasKirna/odysseus that referenced this pull request Jun 2, 2026
Pins actions/github-script@v7 to its exact commit SHA as required by the
workflow-security gate in odysseus-dev#1314 (zizmor --offline --min-severity=low).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PovilasKirna added a commit to PovilasKirna/odysseus that referenced this pull request Jun 2, 2026
Pins actions/github-script@v7 to its exact commit SHA as required by the
workflow-security gate in odysseus-dev#1314 (zizmor --offline --min-severity=low).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@nopoz

nopoz commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the careful read. Lint results against current main first, then the rebase, #1316, and sequencing with #1015.

actionlint is clean across all five workflows (exit 0). hadolint against the existing Dockerfile is green as the workflow runs it: the only finding is DL3008 (unpinned apt versions), which container-scan.yml already ignores on purpose — a -slim base purges old package versions from Debian's repos, so pinning breaks future rebuilds; the base image is pinned instead and tracked by Dependabot's docker ecosystem. So the blocking checks prove green against current main.

On the rebase: the branch is purely additive — eight new files, no path overlap with main (which has no .github/workflows/ yet) or with #1015's ci.yml. The PR's merge-base diff is already exactly those eight files and it merges clean; the already-merged template/Cookbook/etc. files you're seeing come from a two-dot main..branch diff, an artifact of the stale base rather than anything the merge would carry in. Rebasing now would just re-stale as main keeps moving, so I'd rather rebase right before merge — it's a zero-conflict fast-forward whenever you're ready, and that's also when it's worth having the checks run against the latest main. Happy to do it on your signal.

On #1316: small correction — it's already SHA-pinned (actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7), so the unpinned-actions gate won't fire on it; that part's already consistent. I'd suggest we not couple the two PRs beyond that, though. #1314 is self-contained — additive, lint-green, no file overlap with #1316 — so it can land as the baseline on its own. The one genuine interaction is that the zizmor gate will flag #1316's pull_request_target trigger (dangerous-triggers) once both are on the same ref, but that's the gate doing its job: the right place to resolve it is on #1316's own PR check, where a one-line inline # zizmor: ignore[dangerous-triggers] clears it (the usage there is the safe no-checkout pattern, so the suppression is justified). Holding the framework until every in-flight PR is pre-reconciled inverts the goal — better to land the baseline and let the gate triage subsequent PRs, #1316 included. I'll drop the specifics on #1316 directly so they're actionable there rather than buried in this thread.

Sequencing: #1314 has no hard dependency on #1015 (different files, no conflict), so it can merge in either order. It composes with #1015 logically. Your call on order — just let me know and I'll rebase to match.

@pewdiepie-archdaemon

Copy link
Copy Markdown
Collaborator

Closing — unsolicited CI/workflow additions (security scanning suites, dev tooling installs, build workflows, packaging targets) need an issue-first discussion. Project CI direction is intentional and not crowdsourced. Per CONTRIBUTING.md, open an issue describing the gap before opening a tooling PR.

@pewdiepie-archdaemon

Copy link
Copy Markdown
Collaborator

Reopening — the previous close was an agent batch acting on a new "issue-first for CI/tooling" rule, applied retroactively to PRs already in active maintainer review. You'd been thoughtfully responding to my rebase request and the conversation was clearly in progress.

Picking up from your June 2 reply with the actionlint/hadolint results — I'll re-read and respond. Sorry for the noise.

@github-actions github-actions Bot added the needs work PR description incomplete — please update before review label Jun 3, 2026
@alteixeira20
alteixeira20 changed the base branch from main to dev June 4, 2026 23:00
@pewdiepie-archdaemon

Copy link
Copy Markdown
Collaborator

Thanks for pushing this and for the careful follow-up.

Decision from me: approved in direction. Use this security gate scope as the baseline: secret scan, workflow security, dependency review / pip-audit, container scan, and CodeQL with the blocking/advisory split documented here.

Please rebase on the current target branch when ready so the final diff is only the intended governance/security files, then we can use this as the security baseline for branch protection.

I also agree that security-sensitive reports should go through private disclosure first rather than public issues/discussions until triaged.

@vdmkenny
vdmkenny force-pushed the security/ci-bundle branch from 0b76862 to 62a6cce Compare June 8, 2026 11:42
@nopoz
nopoz force-pushed the security/ci-bundle branch from 62a6cce to 3e3e92e Compare June 8, 2026 16:54
@github-actions github-actions Bot added ready for review Description complete — ready for maintainer review and removed needs work PR description incomplete — please update before review labels Jun 8, 2026
@nopoz
nopoz force-pushed the security/ci-bundle branch 2 times, most recently from b5ec21b to 6e33a91 Compare June 8, 2026 18:50
nopoz added a commit to nopoz/odysseus that referenced this pull request Jun 8, 2026
Pin actions to commit SHAs, set persist-credentials: false on every
checkout, and scope token permissions to the jobs that use them. Suppress
the two findings that are safe by design: the description bot's
pull_request_target trigger (no fork code runs) and an intentional
word-split in the docker manifest step.

Clears actionlint and zizmor against dev so the blocking gate from odysseus-dev#1314
can pass once both land.
vdmkenny pushed a commit that referenced this pull request Jun 8, 2026
Pin actions to commit SHAs, set persist-credentials: false on every
checkout, and scope token permissions to the jobs that use them. Suppress
the two findings that are safe by design: the description bot's
pull_request_target trigger (no fork code runs) and an intentional
word-split in the docker manifest step.

Clears actionlint and zizmor against dev so the blocking gate from #1314
can pass once both land.
Consolidates the security CI work into one reviewable change. Adds, as
separate workflow files under .github/workflows/:

- secret-scan.yml      gitleaks (pinned + checksum-verified), full history
- workflow-security.yml actionlint + zizmor, audits the workflows themselves
- dependency-review.yml PR dependency gate + advisory pip-audit
- container-scan.yml    hadolint (blocking) + Trivy image scan (advisory)
- codeql.yml            CodeQL for Python and JS, main + weekly

Plus .github/dependabot.yml (pip/npm/actions/docker), .github/CODEOWNERS,
and docs/security-ci.md explaining each check and the one-time settings.

All additive: no existing files are modified. Actions are pinned to commit
SHAs, tokens default-deny (permissions: {}), advisory scans never block,
and SARIF upload is gated to push so fork PRs do not fail on a read-only
token. Composes with the correctness CI in odysseus-dev#1015.
@nopoz
nopoz force-pushed the security/ci-bundle branch from 6e33a91 to 8184213 Compare June 8, 2026 19:02
@nopoz

nopoz commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Quick status now that #3498 is in: I've rebased this onto the latest dev and everything's green. With the workflow hardening from #3498 merged, the actionlint and zizmor jobs pass cleanly against dev now, where before they were flagging the existing workflows. The diff is still just the eight new governance/security files, nothing else.

If someone picks this up to merge: it's all workflow files, so it'll need to go through the web UI (the API route trips over the missing workflow token scope). There's also a short walkthrough for the one-time branch-protection setup, plus the list of checks to require, in docs/security-ci.md in this PR.

@alteixeira20 alteixeira20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The security-gate direction and blocking/advisory split look appropriate for #2288, and the action pinning looks solid.

I cannot approve the current revision yet because it is 115 commits behind dev, so the June 8 green checks no longer validate the current tree. Please rebase and rerun the complete suite.

Please also reconcile the documented triggers. docs/security-ci.md says pushes to both dev and main are scanned, while the proposed workflows currently target pushes to main only. Since normal development lands on dev, either add dev coverage or update the documented policy explicitly.

One more point before this becomes merge-ready: please confirm that rebuilding the complete image with advisory Trivy on every PR is intentional, including documentation-only PRs. If not, consider limiting the PR job to relevant paths or separating push-only SARIF upload from PR scanning so PR jobs do not request write permissions unnecessarily.

After those points are resolved and the rebased checks pass, this should be suitable for approval.

nopoz and others added 2 commits June 11, 2026 11:30
Address review on odysseus-dev#1314 (points 2 and 3).

container-scan.yml now runs only hadolint (the blocking Dockerfile lint)
and keeps the broad pull_request + push:[main] trigger so the required
check always reports and never hangs a PR.

The advisory image scan moves to container-trivy.yml, split by event:
  - pull_request / workflow_dispatch: build and scan under contents:read
    only, no SARIF upload. The image build runs PR-supplied Dockerfile
    instructions, so this path holds no write scope.
  - push to main: build, scan, and upload SARIF with security-events:write.
    Only this trusted path is granted write.
This stops PR jobs from requesting security-events:write they never use,
and a paths-ignore (matching docker-publish.yml) skips the image rebuild
on docs-only changes.

docs/security-ci.md: correct the trigger description to "every pull
request and every push to main", matching the workflows and the existing
ci.yml convention.

Verified locally: zizmor --offline --min-severity=low and actionlint are
clean on the changed and new workflow files.
@nopoz

nopoz commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed 4139cbf addressing points 2 and 3.

Trigger reconciliation (point 2). The mismatch was in the doc, not the workflows. The push: [main] + pull_request pattern is deliberate and mirrors the existing ci.yml: every contribution targets dev and is gated by the pull_request trigger, and main is fast-forwarded from already-reviewed dev at releases, so the push: [main] run re-scans gated commits and keeps the Security tab current rather than acting as a separate gate. CodeQL's weekly schedule runs on dev since that is the default branch. I have corrected docs/security-ci.md to read "every pull request and every push to main" so the documented policy matches the workflows.

Trivy (point 3). It was not intentional to rebuild on every PR or to carry write scope on PR runs. The advisory scan now lives in its own file, container-trivy.yml, split by event:

  • pull_request / workflow_dispatch: build and scan under contents: read only, no SARIF upload. The build executes PR-supplied Dockerfile instructions, so this path holds no write scope.
  • push to main: build, scan, and upload SARIF with security-events: write. Only this trusted path is granted write.

A paths-ignore (matching docker-publish.yml) skips the image rebuild on docs-only changes. The blocking hadolint job stays in container-scan.yml on the broad trigger so the required check always reports and never hangs a PR. zizmor --offline --min-severity=low and actionlint are clean on the changed and new files.

Rebase (point 1). The June 8 checks are stale; dev has moved and requirements.txt changed in the interim (duckduckgo-search to ddgs, added httpx2), which the suite's pip-audit should pick up. Bringing the branch up to current dev for a full rerun is the remaining step.

@nopoz
nopoz requested a review from alteixeira20 June 11, 2026 18:37

@alteixeira20 alteixeira20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGFM.

Final validation passed on the current head. This is an additive security CI/governance baseline: exactly nine new files, no app-code changes, CI green, docs updated, workflow actions pinned, no unsafe trigger introduced by this PR, and Trivy correctly keeps PR scans read-only while reserving SARIF upload for pushes to main.

@alteixeira20
alteixeira20 merged commit 93825a5 into odysseus-dev:dev Jun 11, 2026
17 checks passed
kootenayalex pushed a commit to kootenayalex/odysseus-mlx that referenced this pull request Jun 16, 2026
Pin actions to commit SHAs, set persist-credentials: false on every
checkout, and scope token permissions to the jobs that use them. Suppress
the two findings that are safe by design: the description bot's
pull_request_target trigger (no fork code runs) and an intentional
word-split in the docker manifest step.

Clears actionlint and zizmor against dev so the blocking gate from odysseus-dev#1314
can pass once both land.
kootenayalex pushed a commit to kootenayalex/odysseus-mlx that referenced this pull request Jun 16, 2026
…#305-310) (odysseus-dev#1314)

* ci: add security scanning suite and governance

Consolidates the security CI work into one reviewable change. Adds, as
separate workflow files under .github/workflows/:

- secret-scan.yml      gitleaks (pinned + checksum-verified), full history
- workflow-security.yml actionlint + zizmor, audits the workflows themselves
- dependency-review.yml PR dependency gate + advisory pip-audit
- container-scan.yml    hadolint (blocking) + Trivy image scan (advisory)
- codeql.yml            CodeQL for Python and JS, main + weekly

Plus .github/dependabot.yml (pip/npm/actions/docker), .github/CODEOWNERS,
and docs/security-ci.md explaining each check and the one-time settings.

All additive: no existing files are modified. Actions are pinned to commit
SHAs, tokens default-deny (permissions: {}), advisory scans never block,
and SARIF upload is gated to push so fork PRs do not fail on a read-only
token. Composes with the correctness CI in odysseus-dev#1015.

* ci(security): isolate Trivy from the Dockerfile lint gate

Address review on odysseus-dev#1314 (points 2 and 3).

container-scan.yml now runs only hadolint (the blocking Dockerfile lint)
and keeps the broad pull_request + push:[main] trigger so the required
check always reports and never hangs a PR.

The advisory image scan moves to container-trivy.yml, split by event:
  - pull_request / workflow_dispatch: build and scan under contents:read
    only, no SARIF upload. The image build runs PR-supplied Dockerfile
    instructions, so this path holds no write scope.
  - push to main: build, scan, and upload SARIF with security-events:write.
    Only this trusted path is granted write.
This stops PR jobs from requesting security-events:write they never use,
and a paths-ignore (matching docker-publish.yml) skips the image rebuild
on docs-only changes.

docs/security-ci.md: correct the trigger description to "every pull
request and every push to main", matching the workflows and the existing
ci.yml convention.

Verified locally: zizmor --offline --min-severity=low and actionlint are
clean on the changed and new workflow files.

---------

Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for review Description complete — ready for maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants