Skip to content

update_precommit_file in stepsecurity_policy_driven_pr causes perpetual drift due to non-deterministic list ordering #47

@arcaven

Description

@arcaven

Description

The update_precommit_file attribute in stepsecurity_policy_driven_pr produces a plan diff on every terraform plan even when no configuration has changed. The API appears to return list elements in a non-deterministic order, causing the provider to detect drift that doesn't exist.

Provider Version

  • step-security/stepsecurity v0.0.20
  • OpenTofu v1.8.11 (also likely affects Terraform)

Resource Configuration

resource "stepsecurity_policy_driven_pr" "this" {
  for_each = var.policy_driven_prs

  owner          = var.github_org
  selected_repos = each.value.selected_repos

  auto_remediation_options = {
    create_pr                        = true
    pin_actions_to_sha               = true
    restrict_github_token_permissions = true
    harden_github_hosted_runner      = true
    secure_docker_file               = true
    update_precommit_file            = [
      "eslint",
      "gitleaks",
      "php-lint-all",
      "shellcheck",
      "trailing-whitespace",
      "end-of-file-fixer",
    ]
  }
}

Observed Behavior

Every plan after a clean apply shows a single element moving position. The element that moves is different each time, it is not always the same item.

First plan after apply:

~ update_precommit_file = [
    + "end-of-file-fixer",
      "eslint",
      # (3 unchanged elements hidden)
      "trailing-whitespace",
    - "end-of-file-fixer",
  ]

Second plan (no changes made):

~ update_precommit_file = [
    + "eslint",
      "gitleaks",
      # (3 unchanged elements hidden)
      "end-of-file-fixer",
    - "eslint",
  ]

The item that rotates is non-deterministic, it varies between plans with no configuration or state changes in between.

Expected Behavior

terraform plan should show no changes when the configuration matches the remote state.

Root Cause Hypothesis

The provider's Read function likely deserializes the API response into a Go map or iterates an unordered structure, then appends elements to the list in iteration order. Since Go map iteration order is randomized, the resulting list order varies per read.

Workaround

lifecycle {
  ignore_changes = [
    auto_remediation_options["update_precommit_file"],
  ]
}

This suppresses the drift but means changes to update_precommit_file require temporarily removing the lifecycle block.

Suggested Fix

Sort update_precommit_file alphabetically (or preserve insertion order) in the provider's Read function before setting it in state.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions