Documentsatlantis
Atlantis Plan State Management
Atlantis Plan State Management
Type
Topic
Status
Published
Created
Jul 9, 2026
Updated
Jul 9, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Atlantis Plan State Management#

Overview#

Atlantis plan state management ensures that an atlantis apply can only execute against a Terraform plan that was generated from the current PR head commit and base branch. This prevents scenarios where a PR's code changes after a plan runs — leaving a stale plan file and outdated DB status that no longer reflect what will actually be applied.

The mechanism has three pillars:

  1. Pre-apply validationapply_plan_validator.go checks live VCS identity against stored PullStatus before allowing apply execution.
  2. BoltDB storage with HeadCommit as a freshness keyboltdb.go uses the PR's head commit (and base branch) to decide whether stored plan state is current or must be reset.
  3. DB write filteringdb_updater.go suppresses writes from stale autoplan or apply results that belong to a different head than what is currently recorded.

These were hardened significantly in PR #6605 to close race windows and fail-closed on any ambiguous or stale state.

Data Model: PullStatus and Freshness Fields#

models.PullStatus is the top-level container written to the database. It holds:

  • Pull — the models.PullRequest snapshot taken at plan time, including HeadCommit and BaseBranch.
  • Projects — a slice of ProjectStatus, each carrying a ProjectPlanStatus enum and policy check results.

Two fields of models.PullRequest drive freshness decisions:

FieldDescription
HeadCommitSHA of the PR's head. Bitbucket Cloud truncates this to 12 characters.
BaseBranchTarget branch name. Same-head retargets (e.g., changing the merge target) produce a different plan and must be replanned.

Apply-eligible ProjectPlanStatus values :

StatusMeaning
PlannedPlanStatusPlan succeeded; not yet applied
PlannedNoChangesPlanStatusPlan returned no changes
PassedPolicyCheckStatusAll policy checks passed or approved
ErroredApplyStatusApply previously errored; retry is allowed

Any other status — including ErroredPlanStatus, ErroredPolicyCheckStatus, DiscardedPlanStatus, AppliedPlanStatus — blocks apply execution .

BoltDB Storage and Freshness Logic#

Atlantis uses an embedded BoltDB database stored as atlantis.db in the data directory . Pull statuses live in the "pulls" bucket , keyed by hostname::repo::pullNum .

UpdatePullWithResults is the main write path. On each plan or apply run it:

  1. Reads the existing PullStatus for the PR.
  2. Calls pullStatusOutdatedForPull to decide whether to reset or merge:
    • If statusPull.HeadCommit != pull.HeadCommitreset: discard all project statuses, start fresh with the new results.
    • If BaseBranch changed → also reset (same-head retargets require a new plan).
    • Otherwise → merge: update only the projects present in newResults, preserving others.
  3. When resetting, policy check statuses from the previous entry are copied forward for matching projects . This preserves policy approvals during the window between a plan write and the subsequent policy-check write.
  4. Overwrites the DB entry with the new PullStatus.

GetPullStatus — simple read; returns nil if no entry exists for the pull key.

Pre-Apply Validation#

DefaultApplyPlanValidator implements two interfaces:

  • ApplyCommandStartValidator.ValidateCommandStartHead — called before building apply commands; fetches the live PR identity and fails immediately if head SHA or base branch has changed since the command started.
  • ApplyPlanValidator.ValidateProjectPlan — the per-project gate executed immediately before each apply step.

ValidateProjectPlan execution flow#

  1. Load PullStatus from DB (or from ctx.PullStatus for API paths).
  2. Fetch live PR identity via LivePullHeadFetcher — a real-time VCS API call returning the current HeadCommit + BaseBranch for all supported platforms (GitHub, GitLab, Azure DevOps, Gitea, Bitbucket Cloud/Server).
  3. Freshness check via pullStatusApplyEligibilityError: compare stored PullStatus.Pull against the live identity. Rejects if:
    • Stored HeadCommit is empty while the live head is known.
    • Stored HeadCommit differs from the live head.
    • Stored BaseBranch is empty or differs from the live base.
  4. Command-start identity check via validateCommandStartIdentity: wraps the error in errStaleCommandHead if the head or base drifted between command start and now.
  5. Project lookup: find the matching project in PullStatus; reject with "no matching plan status" if absent.
  6. Status check via statusAllowedForApplyExecution.
  7. Plan file existence check on disk.
  8. SHA-256 hash verification if ctx.ExpectedPlanHash is set — hashes are captured under the apply lock and rechecked immediately before each apply step.

On any validation failure, rejectProjectPlan deletes the plan file in addition to returning the error, ensuring stale plan files do not persist.

DB Write Filtering (db_updater.go)#

DBUpdater.updateDB is the central DB write path invoked after any plan or apply command completes. It filters results before they reach BoltDB.UpdatePullWithResults:

Stale empty autoplan result : If results is empty and the current DB entry is for a different head/base than the command ran against, the write is skipped. This prevents a no-op autoplan on a stale head from erasing a valid plan state for the current head.

Stale apply result : staleApplyResultForCurrentPull returns true whenever the result set contains any apply-command result and HeadCommit is known. If the current DB entry is for a different head/base, the write is suppressed — apply results from one head cannot overwrite plan state from another.

errStaleCommandHead filtering : Per-project results that carry errStaleCommandHead are dropped before the DB write. If all results are stale-head errors, updateDB returns the current DB status unchanged instead of writing an empty result set.

DirNotExistErr filtering : Results from projects whose directory no longer exists are always dropped before writing; they would never be apply-eligible and would permanently mark the PR as errored.

Atlantis Plan State Management | Dosu