ci: add security-scan + semgrep + dependabot#228
Merged
Conversation
Wires this repo to the org-wide reusable workflows in simple-container-com/actions: - security-scan: TruffleHog (secrets) + Syft/CycloneDX SBOM + Trivy + Grype, sticky PR comment, status gate - semgrep: SC custom ruleset + optional consumer rules / registry packs, sticky PR comment, status gate Both follow the GitHub Security Lab 'preventing pwn requests' split: scan jobs run in pull_request context (read-only token, no secrets, fork-PR safe); comment posting lives in a workflow_run-triggered job that never reads PR code. Adds .github/dependabot.yml with weekly bumps for both github-actions and gomod ecosystems, with minor+patch grouped to reduce PR noise.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…w path-excludes Brings the security-scan workflow to 0 TruffleHog findings while preserving detection coverage. Approach (per Codex review of PR-A's design tradeoffs and the public-actions-repo concern): 1. SOURCE-LEVEL REPLACEMENTS (preferred — no exclusion needed) - MongoDB / Postgres URIs in docs/.md and pkg/**/*_test.go: 'user:pass@host' -> '<USER>:<PASS>@<host>'. Angle brackets break the alphanumeric regex of TruffleHog's URI detectors. ~25 lines across docs and Go tests. - Gitlab CI placeholder text in docs/product-manager/container-security/acceptance-criteria.md: 'gitlab.com/myorg/myrepo' / 'CI_PROJECT_PATH=myorg/myrepo' replaced with '<gitlab-host>/<org>/<repo>' style; defuses the GitLab project-path detector. - Mailgun + Cloudflare fake tokens in docs/.../secrets.yaml: replaced with '<your-mailgun-api-key>' and '<your-cloudflare-api-token>' literals. 2. INLINE TRUFFLEHOG IGNORE (when format-locked but file accepts comments) - pkg/clouds/docker/types_test.go: nested base64 of fake user:password test fixture. TruffleHog scans decoded base64 (per Codex), so no source replacement defeats it without breaking the test. Added '// trufflehog:ignore' Go comment on the affected line with justification. 3. NOSEMGREP suppressions (org-owned bootstrap scripts; same posture as go-aws-lambda-sdk's welder.sh) - .github/workflows/branch-preview.yaml lines 52, 73: 'curl ... | bash' for dist.simple-container.com/sc.sh and welder.simple-container.com/welder.sh. Both are org-owned services. Justifications inline; checksum-pinned welder release tracked as a follow-up. 4. NARROW PATH-EXCLUDES via wrapper input (last resort, file-specific) - docs/docs/examples/.*/secrets\\.yaml — example SC secrets.yaml files containing placeholder GCP service-account JSON; the GCP detector's regex matches even '<service-account>@<project>.iam.gserviceaccount.com' placeholders. - docs/docs/examples/secrets/.*/README\\.md — corresponding example READMEs. - docs/docs/guides/parent-gcp-gke-autopilot\\.md — single guide file. - pkg/api/secrets/testdata/repo/ + pkg/provisioner/testdata/ — raw OpenSSH private-key fixtures (no comment syntax in the file format). These are the only public excludes we accept. The actions repo's PR #2 README explicitly frames such excludes as last-resort + file-specific, given that exclusion patterns in public repos become attacker evasion hints. 5. WIRING - Wrapper now references simple-container-com/actions/.github/workflows/security-scan.yml@feat/secret-scan-extra-excludes for testing. Will bump to @main once that PR merges. Local scan with the new wrapper input + content: 0 findings (down from 39 on first run, with FormBucket already excluded by the actions-repo default). Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
This comment has been minimized.
This comment has been minimized.
…ection
WHAT changed
============
* `pkg/clouds/pulumi/mongodb/util_test.go` — replace mongo URI placeholder
hostnames with `example.com` style. The previous round's `<test-shard>`
used angle brackets, which are not valid URI characters; `url.Parse`
silently returned the raw input and the test broke. example.com
hostnames parse normally and don't trip TruffleHog's MongoDB detector.
* `welder.yaml` — `docker-login` task no longer bootstraps `sc` via
`bash <(curl … sc.sh)`. The CI workflow now installs `sc` upstream
via the `install-sc` composite, so welder can use the binary already
on PATH. Removes a curl-pipe-to-shell finding inside CI-executed code
(welder.yaml is invoked by `welder run` on the runner, so it IS in
scope for our shell rules).
* `.github/workflows/*.yml{,aml}` — workflow hardening:
- **Composites instead of curl-pipe** for tool installs and Telegram
notifications: `simple-container-com/actions/install-sc@main`,
`install-welder@main`, `notify-telegram@main`. Replaces
`curl … | bash`, `bash <(curl …)`, and `yanzay/notify-telegram@v0.1.0`
(third-party, tag-pinned) at all consumer sites.
- **Script-injection mitigation** for attacker-controlled values.
Heredocs that wrote `${{ github.event.head_commit.message }}` into
`/tmp/commit_message.txt` now route the value through `env:` and
`printf` to the file. Same pattern for `${{ github.ref_name }}`
in docker-buildx tag construction and in echoes.
- **`actions/checkout` pinned by SHA** to `v6.0.2`
(`de0fac2e4500dabe0009e67214ff5f5447ce83dd`). Replaces the floating
`@v4` tag, which would also have started warning about Node.js 20
deprecation in June 2026.
* `.semgrepignore` — `sc.sh` (the published end-user installer; runs on
user machines, different threat model from CI).
* `.github/workflows/security-scan.yml` — drop the temporary "@feat"
branch comment now that `simple-container-com/actions` PR #2 merged.
* `.github/workflows/branch-preview.yaml` — preview-build step summary
no longer hands users `curl … | bash`; instead it shows the
`install-sc` action invocation pinned to the preview version.
WHY
===
PR #228 added the security-scan + Semgrep + Dependabot workflows. The
first run on `ci/security-scans` flagged 26 ERROR-severity Semgrep
findings (16 curl-pipe-to-shell, 10 script-injection) and 15 TruffleHog
findings (cross-ref bug — `actions@main` pre-merge — now resolved).
This commit clears all of them at the source rather than via
suppressions. Side effects: removes one third-party action with an
unpinned tag (`yanzay`), prevents the Telegram bot token from leaking
in CI logs (handled inside the new composite via `::add-mask::`), and
gets ahead of the Node.js 20 deprecation.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Re-run TruffleHog over PR #228 was flagging the test's `want:` literal because the rendered post-injection URI matched the MongoDB detector's `<scheme>://<user>:<password>@<host>` shape — even with `example.com` hosts, the connection-string structure itself triggers the detector. Refactor the test to: 1. Call AppendUserPasswordAndDBToMongoUri. 2. Parse the result with `net/url`. 3. Assert: scheme + host + raw query unchanged from input; user info exactly matches the supplied user/password; path becomes `/<dbName>`. This covers the same behavior as the prior full-string equality check (the function is itself just `url.Parse` + assignment + `String()`), without any `mongodb://user:pass@host` literal in source. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
smecsia
previously approved these changes
May 7, 2026
Replace the file-level `.semgrepignore` exclusion with a single `# nosemgrep: shell-curl-pipe-to-shell` comment above the one problematic line in `sc.sh` (the upstream pulumi installer bootstrap). Why: blanket-ignoring the whole file means any future curl-pipe added to `sc.sh` for any other reason would also slip through. With a per-line ignore, only the specific pulumi-installer line is exempt and everything else in `sc.sh` stays in-scope for the shell rules. `.semgrepignore` is now empty and removed. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
smecsia
previously approved these changes
May 7, 2026
…text/suffix Wire the api workflows to the new notify-telegram inputs (clickable title inline, no separate URL line, no Telegram preview card). Per workflow: * branch.yaml (pull_request) — link-url = PR html_url; link-text = `PR #N: <title>`. Falls back to run URL + workflow name when somehow triggered without a PR. * branch-preview.yaml (workflow_dispatch) — link-url = run URL; link-text = `v<preview-version>`. * push.yaml (push to main) — link-url = head commit URL with run URL fallback; link-text = `v<release-version>`. * build-staging.yml (push to main) — link-url = head commit URL with run URL fallback; link-text = workflow name (job-level VERSION env isn't visible in the finalize job, and adding an inter-job output just for this is more change than warranted). Branch ref pinned to `@feat/notify-telegram-append-run-url` for testing the actions PR end-to-end. Will bump to `@main` after that PR merges. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Run 25516915000 startup-failed (0 jobs) because the link-text value:
${{ ... format('PR #{0}: {1}', ...) || ... }}
was an unquoted YAML scalar. The `: ` inside the format() string
literal got interpreted by the YAML parser as a key/value boundary
inside the scalar, which then made the embedded `'` look like an
unterminated quote to the GHA expression lexer (actionlint reported
"unexpected EOF while lexing end of string literal").
Wrap the whole expression in double quotes so YAML treats it as one
opaque scalar and forwards it to the expression engine intact.
Single quotes inside (the format() literal) survive YAML double-quoted
parsing without escaping.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
…ge ref Dev feedback: prior text was too vague — "✅ success (228/merge) - by Cre-eD" doesn't tell you what just happened (CI passed? deploy? release?) and "228/merge" is GitHub's auto-merge ref, not the actual branch you'd checkout. Per workflow: branch.yaml: '✅ CI passed: <PR title> on <head_ref> by <author>' branch-preview.yaml: '✅ Preview published: v<version> on <head_ref> by <author>' push.yaml: '🚀 Released: v<version> by <author>' build-staging.yml: '🏗️ Staging built: <workflow> on <head_ref> by <author>' (failure variants use ❗ + "<verb> failed:") Branch source bumped from `steps.extract_git_ref.outputs.branch` (which is `$GITHUB_REF_NAME` = `228/merge` on PR runs) to `github.head_ref || github.ref_name` — head_ref is the source branch on PR events; ref_name is the target on push events. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
smecsia
approved these changes
May 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
simple-container-com/actions:security-scan— TruffleHog + Syft + Trivy + Grype, sticky PR comment, status gatesemgrep— SC custom ruleset + optional consumer rules / registry packs, sticky PR comment, status gate.github/dependabot.ymlfor weekly bumps (github-actions + gomod where applicable, minor+patch grouped)Trust posture
Scan jobs run on
pull_request(not_target), read-only token, no secrets — safe for fork PRs. Comment posting lives in a separateworkflow_run-triggered workflow that never reads PR code.Test plan