Skip to content

Keep empty static analysis blocks consistent after apply - #126

Merged
ryanduffin merged 5 commits into
rduffin/datadog-monitor-objectsfrom
rduffin/static-analysis-empty-block
Oct 6, 2026
Merged

ryanduffin merged 5 commits into
rduffin/datadog-monitor-objectsfrom
rduffin/static-analysis-empty-block

Conversation

@ryanduffin

@ryanduffin ryanduffin commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Several static_analysis configurations on cortex_catalog_entity no longer fail with "Provider produced inconsistent result after apply", and reading static analysis data no longer crashes the provider.

Claude Details

Summary

  • The provider omits empty values from the descriptor it writes (omitempty), so the API returns nothing for them. For an attribute that is optional and not computed, Terraform requires the state after apply to match the configuration, so the provider must keep the configured empty value.
  • The Mend read model returned an object even when the descriptor had no Mend data, and the Veracode lists read as [] instead of null. So a static_analysis block without mend, or a veracode block without sandboxes, also failed the apply, and an import wrote values that the configuration did not have.
  • The parser crashed on a mend block with only one ID list, on numeric or null Mend IDs (the API accepts numbers), and on a veracode block without applicationNames or with null or numeric names.

Changes

  • New keepEmptyObject helper (empty_values.go): where the prior value and the value read from the API are both empty (null, an empty list or set, or an object of empty values), at any depth, it keeps the prior value. Create and Update keep the planned static_analysis this way, and Read keeps the prior state. A value set outside Terraform still reads into state.
  • Mend reads as null when it has no IDs, as the other integrations already do. A missing Mend ID list or Veracode list reads as null, not [].
  • New stringValues parser helper for Mend IDs and Veracode application names: it keeps strings, converts numbers and booleans to strings, and skips null values and nested lists or maps. Mend also drops empty IDs, as before; Veracode keeps empty names, as before. The ID lists and applicationNames use checked assertions.
  • New in-memory fake of the catalog entity routes (catalog_entity_fake_test.go): upsert, descriptor read, and delete. Like the backend, it stores the descriptor as submitted and returns it on read. The new tests run the resource through real Terraform plan, apply, refresh, and import with resource.UnitTest, without a Cortex tenant.
  • CHANGELOG entry.

Not in this PR

  • An empty string is not treated as empty (for example code_cov.owner = "" or sonar_qube.alias = ""). These configurations failed before this PR too.
  • Importing an entity whose configuration has an empty block shows a one-time update from null to {}. The API stores nothing for an empty block, so the import cannot know about it.
  • Other unchecked casts in the static analysis parser (Veracode sandboxes, SonarQube) can still panic on malformed input.
  • A numeric ID that the API returns in a non-decimal form (for example hex or exponent notation) reads as its decimal value. Before this PR, any numeric ID crashed the provider.

Test plan

  • go test ./...: all packages pass.
    • TestUnitCatalogEntity_EmptyStaticAnalysis: {}, { mend = {} }, and empty ID lists. Before the fix, all three fail with "Provider produced inconsistent result after apply". Each case also checks that the fake stores no x-cortex-static-analysis.
    • TestUnitCatalogEntity_StaticAnalysisWithOneIntegration: SonarQube only, Veracode names only, and Veracode sandboxes only, each with an import check.
    • TestUnitCatalogEntity_ImportThenPlanIsEmpty: seeds the fake, imports, and requires an empty plan. ImportStateVerify treats an empty list as absent, so this catches [] in state.
    • TestUnitCatalogEntity_MendWithOneIdList, _MendWithBothIdLists, _UpdateMendToEmptyAndBack, and _EmptyStaticAnalysisShowsRemoteChange (a value set outside Terraform under a configured empty block reaches state).
    • TestKeepEmptyObject and TestKeepEmptyObject_Nested, the Mend and Veracode FromApiModel model tests, and the Mend and Veracode parser tests.
    • Mutation checks: reverting each fix makes at least one of these tests fail.
  • gofmt -l, go vet ./..., and golangci-lint run (v2.14.0): clean.
  • make testacc: not run locally. CI runs it.

🤖 Generated with Claude Code

@ryanduffin
ryanduffin added this pull request to stack #128 October 6, 2026 15:30
ryanduffin and others added 2 commits October 6, 2026 14:44
The provider omits an empty static_analysis block, mend block, or Mend
ID list from the descriptor it writes, so the API reads them back as
absent. Terraform requires the state after apply to match a configured
value, so these configurations failed with "Provider produced
inconsistent result after apply".

Create, Update, and Read now keep the planned or prior static_analysis
value where it and the API value are both empty. A Mend ID list that
the API leaves out now reads as null, not as an empty list.

A mend block with only one ID list also crashed the provider on read,
because the parser expected both lists. The parser now treats a missing
list as empty.

The new unit tests run the resource against an in-memory fake of the
catalog entity routes, without a Cortex tenant.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ryanduffin
ryanduffin force-pushed the rduffin/static-analysis-empty-block branch from 4057c7f to 4cb6fa0 Compare October 6, 2026 18:46
ryanduffin and others added 3 commits October 6, 2026 15:03
The Mend read model returned an object even when the descriptor had no
Mend IDs, so any static_analysis block without mend failed the apply
with an inconsistent result. keepEmptyObject hid this on Create,
Update, and Read, but an import still wrote mend = {}. Mend now reads
as null when it has no IDs, as the other integrations already do, and
the Veracode lists read as null when they are absent.

The parser no longer crashes on numeric or null Mend IDs, which the API
accepts, or on a Veracode block without applicationNames.

New tests cover a static_analysis block with one integration and an
import, an update from Mend IDs to an empty block and back, and a
remote change under a configured empty block. Comments now say that
the provider, not the API, omits the empty values.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Veracode application names now go through the same conversion as Mend
IDs, so a null or numeric name no longer crashes the provider. Other
scalar IDs, such as floats or values above the int64 range, read as
strings instead of being dropped.

ImportStateVerify treats an empty list as absent, so a new test seeds
the fake, imports, and requires an empty plan. It catches an empty
list read into state where the configuration has none.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moving Veracode application names to stringValues dropped empty names,
which the provider writes and the API stores, so a configuration with
an empty name failed the apply. Only Mend drops empty IDs now, as it
did before. stringValues also skips nested lists and maps instead of
converting them to strings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ryanduffin
ryanduffin marked this pull request as ready for review October 6, 2026 20:24
@ryanduffin
ryanduffin requested a review from gvillenave October 6, 2026 20:25
@ryanduffin
ryanduffin merged commit 35452c3 into main Oct 6, 2026
9 of 10 checks passed
@ryanduffin
ryanduffin deleted the rduffin/static-analysis-empty-block branch October 6, 2026 20:43
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.

2 participants