Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure that all errors are checked during read, not just tfresource.NotFound #38292

Merged
merged 5 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .changelog/38292.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
```release-note:bug
aws_dx_lag: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_dynamodb_kinesis_streaming_destination: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_ec2_capacity_block_reservation: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_route_table: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_opensearchserverless_access_policy: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_opensearchserverless_collection: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_opensearchserverless_security_config: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_opensearchserverless_security_policy: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_opensearchserverless_vpc_endpoint: Checks for errors other than NotFound when reading.
```

```release-note:bug
aws_ram_principal_association: Checks for errors other than NotFound when reading.
```
183 changes: 183 additions & 0 deletions .ci/semgrep/errors/error-checks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package main

import (
"context"
"errors"
"time"

"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func test1() {
_, err := call()

// ruleid: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}

return
}

func test2() {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}

if err != nil {
return
}

return
}

func test3() {
_, err := call()

if err != nil {
// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}
return
}

return
}

func test4() {
_, err := call()

if err == nil {
return
// ok: notfound-without-err-checks
} else if tfresource.NotFound(err) {
return
} else {
return
}
}

func test5() {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
} else if err != nil {
return
} else {
return
}
}

func test6() error {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}

return err
}

func test7() {
for {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
continue
}
}

return err
}

func test8() {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}

if tfawserr.ErrCodeEquals(err, "SomeError") {
return
}

if err != nil {
return
}

return
}

func test9() {
_, err := call()

if err != nil {
// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
} else {
return
}
}

return
}

func test10() {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
} else if err != nil {
return
}

return
}

func test11() {
ctx := context.Background()

tfresource.RetryWhen(ctx, 1*time.Second, nil, func(err error) (bool error) {
// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return true, err
}

return false, err
})
}

func test12() {
_, err := call()

// ok: notfound-without-err-checks
if tfresource.NotFound(err) {
return
}

if PreCheckSkipError(err) {
return
}

if err != nil {
return
}

return
}

func call() (any, error) {
return nil, errors.New("error")
}
59 changes: 59 additions & 0 deletions .ci/semgrep/errors/error-checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
rules:
- id: notfound-without-err-checks
languages: [go]
message: When checking for tfresource.NotFound() errors, typically other error conditions should be checked.
patterns:
- pattern: |
if tfresource.NotFound($ERR) { ... }
- pattern-not-inside: |
if tfresource.NotFound($ERR) { ... }
if $ERR != nil { ... }
- pattern-not-inside: |
if tfresource.NotFound($ERR) { ... }
if $FUNC($ERR, ...) { ... }
if $ERR != nil { ... }
- pattern-not-inside: |
if err != nil {
if tfresource.NotFound($ERR) { ... }
return ...
}
- pattern-not-inside: |
if err != nil {
if tfresource.NotFound($ERR) {
...
} else {
...
}
}
- pattern-not-inside: |
if err == nil {
...
} else if tfresource.NotFound($ERR) {
...
} else { ... }
- pattern-not-inside: |
if tfresource.NotFound($ERR) {
...
} else if err != nil {
...
} else {
...
}
- pattern-not-inside: |
if tfresource.NotFound($ERR) {
...
}
return $ERR
- pattern-not-inside: |
if tfresource.NotFound($ERR) {
continue
}
- pattern-not-inside: |
if tfresource.NotFound($ERR) {
...
} else if err != nil {
...
}
- pattern-not-inside: |
tfresource.RetryWhen(...)
severity: ERROR
27 changes: 27 additions & 0 deletions .github/workflows/semgrep-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,42 @@ env:
SEMGREP_ARGS: --error --quiet

jobs:
semgrep-validate:
Copy link
Member

@justinretzolk justinretzolk Jul 9, 2024

Choose a reason for hiding this comment

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

I do wonder if we could combine these into steps of a single job, rather than distinct ones, but it's not something I'd hold off on merging for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered validating all of the Semgrep files in this job, and then making all the jobs depend on it, but figured this was fewer changes

name: Validate Code Quality Rules
runs-on: ubuntu-latest
container:
image: "returntocorp/semgrep:1.52.0"
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- run: |
semgrep --validate \
--config .ci/.semgrep.yml \
--config .ci/.semgrep-constants.yml \
--config .ci/.semgrep-test-constants.yml \
--config .ci/semgrep/

semgrep-test:
name: Semgrep Rule Tests
needs: [semgrep-validate]
runs-on: ubuntu-latest
container:
image: "returntocorp/semgrep:1.52.0"
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- run: |
semgrep --quiet --test .ci/semgrep/

semgrep:
name: Code Quality Scan
needs: [semgrep-test]
runs-on: ubuntu-latest
container:
image: "returntocorp/semgrep:1.52.0"
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- run: |
semgrep $SEMGREP_ARGS \
--exclude .ci/semgrep/**/*.go \
--config .ci/.semgrep.yml \
--config .ci/.semgrep-constants.yml \
--config .ci/.semgrep-test-constants.yml \
Expand Down
20 changes: 14 additions & 6 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,11 @@ sanity: prereq-go ## Run sanity check (failures allowed)

semgrep: semgrep-code-quality semgrep-naming semgrep-naming-cae semgrep-service-naming ## [CI] Run all CI Semgrep checks

semgrep-all: semgrep-validate ## Run semgrep on all files
semgrep-all: semgrep-test semgrep-validate ## Run semgrep on all files
@echo "make: Running Semgrep checks locally (must have semgrep installed)..."
@semgrep $(SEMGREP_ARGS) \
$(if $(filter-out $(origin PKG), undefined),--include $(PKG_NAME),) \
--exclude .ci/semgrep/**/*.go \
--config .ci/.semgrep.yml \
--config .ci/.semgrep-constants.yml \
--config .ci/.semgrep-test-constants.yml \
Expand All @@ -479,11 +480,12 @@ semgrep-all: semgrep-validate ## Run semgrep on all files
--config 'r/dgryski.semgrep-go.oddifsequence' \
--config 'r/dgryski.semgrep-go.oserrors'

semgrep-code-quality: semgrep-validate ## [CI] Semgrep Checks / Code Quality Scan
semgrep-code-quality: semgrep-test semgrep-validate ## [CI] Semgrep Checks / Code Quality Scan
@echo "make: Semgrep Checks / Code Quality Scan..."
@echo "make: Running Semgrep checks locally (must have semgrep installed)"
semgrep $(SEMGREP_ARGS) \
@semgrep $(SEMGREP_ARGS) \
$(if $(filter-out $(origin PKG), undefined),--include $(PKG_NAME),) \
--exclude .ci/semgrep/**/*.go \
--config .ci/.semgrep.yml \
--config .ci/.semgrep-constants.yml \
--config .ci/.semgrep-test-constants.yml \
Expand Down Expand Up @@ -512,6 +514,7 @@ semgrep-fix: semgrep-validate ## Fix Semgrep issues that have fixes
@echo "make: WARNING: This will not fix rules that don't have autofixes"
@semgrep $(SEMGREP_ARGS) --autofix \
$(if $(filter-out $(origin PKG), undefined),--include $(PKG_NAME),) \
--exclude .ci/semgrep/**/*.go \
--config .ci/.semgrep.yml \
--config .ci/.semgrep-constants.yml \
--config .ci/.semgrep-test-constants.yml \
Expand Down Expand Up @@ -543,6 +546,11 @@ semgrep-naming-cae: semgrep-validate ## [CI] Semgrep Checks / Naming Scan Caps/A
$(if $(filter-out $(origin PKG), undefined),--include $(PKG_NAME),) \
--config .ci/.semgrep-caps-aws-ec2.yml

semgrep-test: semgrep-validate ## Test Semgrep configuration files
@echo "make: Running Semgrep rule tests..."
@semgrep --quiet \
--test .ci/semgrep/

semgrep-service-naming: semgrep-validate ## [CI] Semgrep Checks / Service Name Scan A-Z
@echo "make: Semgrep Checks / Service Name Scan A-Z..."
@echo "make: Running Semgrep checks locally (must have semgrep installed)"
Expand Down Expand Up @@ -604,7 +612,7 @@ sweeper-unlinked: go-build ## [CI] Provider Checks / Sweeper Functions Not Linke
grep --count --extended-regexp 'internal/service/[a-zA-Z0-9]+\.sweep[a-zA-Z0-9]+$$'` ; \
echo "make: sweeper-unlinked: found $$count, expected 0" ; \
[ $$count -eq 0 ] || \
(echo "Expected `strings` to detect no sweeper function names in provider binary."; exit 1)
(echo "Expected `strings` to detect no sweeper function names in provider binary."; exit 1)

t: prereq-go fmt-check ## Run acceptance tests (similar to testacc)
TF_ACC=1 $(GO_VER) test ./$(PKG_NAME)/... -v -count $(TEST_COUNT) -parallel $(ACCTEST_PARALLELISM) $(RUNARGS) $(TESTARGS) -timeout $(ACCTEST_TIMEOUT)
Expand Down Expand Up @@ -637,8 +645,8 @@ testacc: prereq-go fmt-check ## Run acceptance tests
testacc-lint: ## [CI] Acceptance Test Linting / terrafmt
@echo "make: Acceptance Test Linting / terrafmt..."
@find $(SVC_DIR) -type f -name '*_test.go' \
| sort -u \
| xargs -I {} terrafmt diff --check --fmtcompat {}
| sort -u \
| xargs -I {} terrafmt diff --check --fmtcompat {}

testacc-lint-fix: ## Fix acceptance test linter findings
@echo "make: Fixing Acceptance Test Linting / terrafmt..."
Expand Down
Loading
Loading