Skip to content

fix(semgrep): go-aws-rds-no-storage-encryption — require secure-by-default lo.FromPtrOr(_, true)#9

Open
Cre-eD wants to merge 2 commits intomainfrom
fix/semgrep-rds-storage-encryption-runtime-helper-fp
Open

fix(semgrep): go-aws-rds-no-storage-encryption — require secure-by-default lo.FromPtrOr(_, true)#9
Cre-eD wants to merge 2 commits intomainfrom
fix/semgrep-rds-storage-encryption-runtime-helper-fp

Conversation

@Cre-eD
Copy link
Copy Markdown
Contributor

@Cre-eD Cre-eD commented May 8, 2026

Context

Surfaced as a false positive in simple-container-com/api#238. Two sites:

  • pkg/clouds/pulumi/aws/rds_mysql.go:137StorageEncrypted: sdk.Bool(lo.FromPtr(dbConfig.StorageEncrypted))
  • pkg/clouds/pulumi/aws/rds_postgres.go:121StorageEncrypted: sdk.Bool(lo.FromPtr(postgresCfg.StorageEncrypted))

Both intentionally use a runtime-config opt-in pattern paired with IgnoreChanges([]string{"storageEncrypted"}) on the resource opts — a migration-safe design that the rule's previous strict-literal-only suppression (Bool(true) / true) didn't account for.

Fix

Add a third pattern-not-regex accepting the specific <ptr>.Bool(lo.FromPtr(<expr>)) shape:

StorageEncrypted:\s*\w+\.Bool\(lo\.FromPtr\([^()\n]+\)\)

Narrow on purpose:

  • Requires the lo.FromPtr(...) literal — arbitrary wrappers (e.g. sdk.Bool(someFn())) still fire the rule.
  • Single-line via [^()\n]+ — no multi-line bypass.
  • Does not verify the IgnoreChanges pairing in regex; the wrapper shape itself is the design signal. Documented in the inline comment.

Tests

semgrep-scan/tests/go_cases.go adds 3 cases:

  • // ok:sdk.Bool(lo.FromPtr(cfg.X)) — must NOT fire
  • // ok:pulumi.Bool(lo.FromPtr(cfg.X)) — must NOT fire (different prefix)
  • // ruleid:sdk.Bool(someRuntimeBool()) — must STILL fire (arbitrary wrapper, no lo.FromPtr)

Existing fixtures (literal true, literal false, omit, and Bool(false)) all continue to behave as before.

33/33 cases passed for go_cases.go
38/38 cases passed for shell.bash
56/56 cases passed for cases.yml
All semgrep rule tests passed.

Real-world verification

After this change, scanning simple-container-com/api/pkg/clouds/pulumi/aws/ produces 0 findings for go-aws-rds-no-storage-encryption — both former FPs cleared, no regression on the literal-disable / omit cases that exist elsewhere in the same package.

Test plan

  • bash semgrep-scan/run-tests.sh green locally
  • Re-scan against simple-container-com/api: FPs cleared
  • semgrep-self-test workflow passes on this branch
  • Confirm api PR #238's Semgrep status check turns green after merge (no api code change needed)

…ntime opt-in shape

PR #238 in simple-container-com/api flagged this rule as a false-
positive on two sites in pkg/clouds/pulumi/aws/rds_{mysql,postgres}.go,
both using a runtime-config opt-in pattern:

    StorageEncrypted: sdk.Bool(lo.FromPtr(dbConfig.StorageEncrypted))

`lo.FromPtr(*bool)` returns false for nil (preserves legacy default)
or the explicit value otherwise. Each call site is paired with
`IgnoreChanges([]string{"storageEncrypted"})` on the resource opts so
flipping the bit later doesn't trigger destructive replacement of
pre-existing unencrypted instances — a deliberate migration-safe
design that the rule's strict CIS-RDS.3 reading didn't account for.

Fix: add a third `pattern-not-regex` that suppresses the specific
`<ptr>.Bool(lo.FromPtr(<expr>))` shape. The regex is narrow:

    StorageEncrypted:\s*\w+\.Bool\(lo\.FromPtr\([^()\n]+\)\)

- Requires `lo.FromPtr(...)` literal, not arbitrary wrappers, so a
  developer wrapping in some other helper still fires the rule.
- Single-line via `[^()\n]+` so multi-line shenanigans don't
  accidentally bypass.
- Does NOT verify the IgnoreChanges pairing in regex; the wrapper
  shape itself is the design signal.

The literal-`false` and `Bool(false)` cases continue to fire (covered
by existing fixtures + a new explicit guard test that uses
`sdk.Bool(<arbitrary expr>)` to confirm only the lo.FromPtr shape is
suppressed, not any wrapper).

Tests: 33/33 in go_cases.go (was 30) — added two `// ok:` cases for
the runtime-helper shape (sdk.Bool / pulumi.Bool variants) and one
`// ruleid:` guard for the arbitrary-wrapper case. `bash
semgrep-scan/run-tests.sh` is green (127/127 across all rule files).

Verified: 0 findings of `go-aws-rds-no-storage-encryption` against
simple-container-com/api/pkg/clouds/pulumi/aws/ after this change.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Security Scan Results

Repository: actions | Commit: e6e3f7f

Check Status Details
✅ Secret Scan Pass No secrets detected
⏩ Dependencies Skipped -

Scanned at 2026-05-09 08:18 UTC

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Semgrep Scan Results

Repository: actions | Commit: e6e3f7f

Check Status Details
✅ Semgrep Pass 0 total findings (no error/warning)

Scanned at 2026-05-09 08:18 UTC

…ure default

Earlier draft of this PR whitelisted any `<ptr>.Bool(lo.FromPtr(*ptr))`
shape — but `lo.FromPtr(nil)` returns the type's zero value (false for
*bool), so that suppression accepted code that defaults to UNENCRYPTED
when a customer hasn't set the field. That permanently lowers the rule
below CIS-AWS RDS.3 and was the wrong call.

Replaced with a tighter whitelist that requires the literal-true
fallback:

  StorageEncrypted:\s*\w+\.Bool\(lo\.FromPtrOr\([^()\n]+,\s*true\s*\)\)

What still fires:
  - bare `StorageEncrypted: false` and `StorageEncrypted: Bool(false)`
  - bare `lo.FromPtr(*ptr)` (defaults to false → unencrypted)
  - `lo.FromPtrOr(*ptr, false)` (explicit insecure default)
  - any other arbitrary wrapper around a runtime expression

What's suppressed:
  - `StorageEncrypted: true` (literal)
  - `<ptr>.Bool(true)` (canonical Pulumi truthy)
  - `<ptr>.Bool(lo.FromPtrOr(*ptr, true))` (secure-by-default
    runtime config)

The runtime-config form must be paired with
`IgnoreChanges([]string{"storageEncrypted"})` on the resource opts to
keep the default-flip safe for pre-existing unencrypted instances.
The pairing isn't regex-verified; the wrapper shape + literal-true
fallback are the design signal.

Tests
=====

`semgrep-scan/tests/go_cases.go` updated:
- Renamed positive cases to `rdsRuntimeSecure{Sdk,Pulumi}` (was
  `rdsRuntimeOptIn{Sdk,Pulumi}`) and switched to the
  `lo.FromPtrOr(_, true)` shape.
- Added `// ruleid:` for `lo.FromPtr(*ptr)` (bare-FromPtr-still-fires)
  and `lo.FromPtrOr(*ptr, false)` (explicit-insecure-fallback).
- Kept arbitrary-wrapper guard.

Total go_cases.go: 35/35 passes; full ruleset 129/129 across all
fixtures.

Companion: simple-container-com/api#240 flips the call sites in
rds_{mysql,postgres}.go from `lo.FromPtr(*ptr)` to
`lo.FromPtrOr(*ptr, true)`, satisfying both this rule and CIS-AWS
RDS.3 going forward.

Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
@Cre-eD Cre-eD changed the title fix(semgrep): go-aws-rds-no-storage-encryption — accept lo.FromPtr runtime opt-in shape fix(semgrep): go-aws-rds-no-storage-encryption — require secure-by-default lo.FromPtrOr(_, true) May 9, 2026
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