test/openagents/deployments_test.exs

main at 58e6347eeb72 · 29 KB

defmodule OpenAgents.DeploymentsTest do
  use OpenAgents.DataCase, async: true

  import OpenAgents.AccountsFixtures
  import OpenAgents.DeploymentsFixtures

  alias OpenAgents.Deployments
  alias OpenAgents.Deployments.Principal
  alias OpenAgents.Deployments.Providers.Fake
  alias OpenAgents.Deployments.Run
  alias OpenAgents.Deployments.Worker

  setup do
    owner = repository_user_fixture("deploy-owner")
    repository = repository_with_member_fixture(owner, %{visibility: "private"}, "owner")

    %{owner: owner, repository: repository, principal: Principal.user(owner)}
  end

  describe "environments" do
    test "a writable member defines an environment and reads its protection", context do
      environment =
        environment_fixture(context.repository, context.owner, %{
          "protection" => %{"required_checks" => ["build"], "required_approvals" => 1}
        })

      assert environment.provider == "fake"
      assert environment.protection.required_checks == ["build"]

      assert {:ok, [^environment]} =
               Deployments.list_environments(context.repository, context.principal)
    end

    test "an unknown provider is refused before anything is written", context do
      assert {:error, :unknown_provider} =
               Deployments.put_environment(context.repository, context.principal, %{
                 "name" => "production",
                 "kind" => "production",
                 "provider" => "Elixir.System",
                 "protection" => %{}
               })
    end

    test "a non-member cannot define an environment", context do
      stranger = Principal.user(repository_user_fixture("deploy-stranger"))

      assert {:error, {:forbidden, :not_writable}} =
               Deployments.put_environment(context.repository, stranger, %{
                 "name" => "production",
                 "kind" => "production",
                 "provider" => "fake",
                 "protection" => %{}
               })
    end

    test "a private repository's deployments are unreadable by a non-member", context do
      environment_fixture(context.repository, context.owner)
      stranger = Principal.user(repository_user_fixture("deploy-outsider"))

      assert {:error, {:forbidden, :not_a_member}} =
               Deployments.list_environments(context.repository, stranger)
    end
  end

  describe "requesting a deployment" do
    setup context do
      %{environment: environment_fixture(context.repository, context.owner)}
    end

    test "an unprotected environment queues immediately", context do
      run = run_fixture(context.repository, context.owner)

      assert run.state == "queued"
      assert run.provider == "fake"
      assert Enum.any?(run.policy_explanation, &(&1["rule"] == "required_checks"))
    end

    test "a commit the repository never received is refused", context do
      assert {:error, :unknown_commit} =
               Deployments.request_deployment(
                 context.repository,
                 context.principal,
                 %{
                   "environment" => "production",
                   "commit_sha" => commit_sha(),
                   "artifact_digest" => artifact_digest(),
                   "source_ref" => "refs/heads/main",
                   "idempotency_key" => "unknown-commit"
                 },
                 commit_store: fn _repository, _sha -> {:error, :unknown_commit} end
               )
    end

    test "replaying an idempotency key with the same bytes returns the same run", context do
      attrs = %{"idempotency_key" => "same-key-1234"}

      first = run_fixture(context.repository, context.owner, attrs)
      second = run_fixture(context.repository, context.owner, attrs)

      assert first.id == second.id
    end

    test "replaying an idempotency key with different bytes is a conflict", context do
      run_fixture(context.repository, context.owner, %{"idempotency_key" => "conflict-1234"})

      assert {:error, :idempotency_conflict} =
               Deployments.request_deployment(
                 context.repository,
                 context.principal,
                 %{
                   "environment" => "production",
                   "commit_sha" => String.duplicate("ef", 20),
                   "artifact_digest" => artifact_digest(),
                   "source_ref" => "refs/heads/main",
                   "idempotency_key" => "conflict-1234"
                 },
                 commit_store: any_commit()
               )
    end

    test "an invalid commit sha never reaches the database", context do
      assert {:error, changeset} =
               Deployments.request_deployment(
                 context.repository,
                 context.principal,
                 %{
                   "environment" => "production",
                   "commit_sha" => "abc",
                   "artifact_digest" => artifact_digest(),
                   "source_ref" => "refs/heads/main",
                   "idempotency_key" => "bad-commit-1234"
                 },
                 commit_store: any_commit()
               )

      assert %{commit_sha: ["has invalid format"]} = errors_on(changeset)
    end

    test "a platform operator holds no tenant deployment authority", context do
      operator = Principal.operator(context.owner)

      assert {:error, {:forbidden, :operator_is_not_tenant}} =
               Deployments.request_deployment(
                 context.repository,
                 operator,
                 %{
                   "environment" => "production",
                   "commit_sha" => commit_sha(),
                   "artifact_digest" => artifact_digest(),
                   "source_ref" => "refs/heads/main",
                   "idempotency_key" => "operator-1234"
                 },
                 commit_store: any_commit()
               )
    end
  end

  describe "repository boundary" do
    setup context do
      environment_fixture(context.repository, context.owner)

      other_owner = repository_user_fixture("deploy-other-owner")
      other_repository = repository_with_member_fixture(other_owner, %{}, "owner")
      environment_fixture(other_repository, other_owner)

      %{
        run: run_fixture(context.repository, context.owner),
        other_repository: other_repository,
        other_principal: Principal.user(other_owner)
      }
    end

    test "a run cannot be read through another repository", context do
      assert {:error, {:forbidden, :cross_repository}} =
               Deployments.fetch_run(
                 context.other_repository,
                 context.other_principal,
                 context.run.id
               )
    end

    test "a run cannot be cancelled through another repository", context do
      assert {:error, {:forbidden, :cross_repository}} =
               Deployments.cancel_run(
                 context.other_repository,
                 context.other_principal,
                 context.run.id
               )
    end

    test "a run cannot be approved through another repository", context do
      assert {:error, {:forbidden, :cross_repository}} =
               Deployments.decide_run(
                 context.other_repository,
                 context.other_principal,
                 context.run.id,
                 "approved"
               )
    end

    test "an unknown run id is not found rather than forbidden", context do
      assert {:error, :run_not_found} =
               Deployments.fetch_run(context.repository, context.principal, Ecto.UUID.generate())

      assert {:error, :run_not_found} =
               Deployments.fetch_run(context.repository, context.principal, "not-a-uuid")
    end
  end

  describe "required checks" do
    setup context do
      environment =
        environment_fixture(context.repository, context.owner, %{
          "protection" => %{"required_checks" => ["build"]}
        })

      %{environment: environment, run: run_fixture(context.repository, context.owner)}
    end

    test "a run waits in checking until evidence for its exact bytes arrives", context do
      assert context.run.state == "checking"

      {:ok, _result} =
        Deployments.publish_check_result(context.repository, context.principal, %{
          "name" => "build",
          "commit_sha" => commit_sha(),
          "artifact_digest" => artifact_digest(),
          "status" => "succeeded"
        })

      assert {:ok, %Run{state: "queued"}} =
               Deployments.fetch_run(context.repository, context.principal, context.run.id)
    end

    test "a green check for different bytes does not admit the run", context do
      {:ok, _result} =
        Deployments.publish_check_result(context.repository, context.principal, %{
          "name" => "build",
          "commit_sha" => String.duplicate("ef", 20),
          "artifact_digest" => artifact_digest(),
          "status" => "succeeded"
        })

      assert {:ok, %Run{state: "checking"}} =
               Deployments.fetch_run(context.repository, context.principal, context.run.id)
    end

    test "a different artifact under the same check name is a separate result", context do
      for artifact <- [artifact_digest(), "sha256:" <> String.duplicate("d", 64)] do
        {:ok, _result} =
          Deployments.publish_check_result(context.repository, context.principal, %{
            "name" => "build",
            "commit_sha" => commit_sha(),
            "artifact_digest" => artifact,
            "status" => "succeeded"
          })
      end

      {:ok, results} =
        Deployments.list_check_results(
          context.repository,
          context.principal,
          commit_sha(),
          artifact_digest()
        )

      assert length(results) == 1
    end

    test "a failed check denies the run durably", context do
      {:ok, _result} =
        Deployments.publish_check_result(context.repository, context.principal, %{
          "name" => "build",
          "commit_sha" => commit_sha(),
          "artifact_digest" => artifact_digest(),
          "status" => "failed"
        })

      assert {:ok, %Run{state: "failed", result_reason: "checks_failed"}} =
               Deployments.fetch_run(context.repository, context.principal, context.run.id)
    end
  end

  describe "approvals" do
    setup context do
      approver = repository_user_fixture("deploy-approver")

      {:ok, _membership} =
        OpenAgents.Repositories.add_member(context.repository, approver, "maintainer")

      environment_fixture(context.repository, context.owner, %{
        "protection" => %{"required_approvals" => 1}
      })

      %{approver: approver, run: run_fixture(context.repository, context.owner)}
    end

    test "a run waits for approval and queues once another member approves", context do
      assert context.run.state == "waiting_for_approval"

      assert {:ok, %Run{state: "queued"}} =
               Deployments.decide_run(
                 context.repository,
                 Principal.user(context.approver),
                 context.run.id,
                 "approved"
               )
    end

    test "the requester cannot approve its own deployment", context do
      assert {:error, {:forbidden, :self_approval}} =
               Deployments.decide_run(
                 context.repository,
                 context.principal,
                 context.run.id,
                 "approved"
               )
    end

    test "a contributor is not an approver under the default policy", context do
      contributor = repository_user_fixture("deploy-contributor")

      {:ok, _membership} =
        OpenAgents.Repositories.add_member(context.repository, contributor, "contributor")

      assert {:error, {:forbidden, :not_an_approver}} =
               Deployments.decide_run(
                 context.repository,
                 Principal.user(contributor),
                 context.run.id,
                 "approved"
               )
    end

    test "a rejection denies the run", context do
      assert {:ok, %Run{state: "failed", result_reason: "rejected"}} =
               Deployments.decide_run(
                 context.repository,
                 Principal.user(context.approver),
                 context.run.id,
                 "rejected"
               )
    end

    test "a workflow grant cannot approve", context do
      {grant, _plaintext} = workflow_grant_fixture(context.repository, context.owner)

      assert {:error, {:forbidden, :operator_is_not_tenant}} =
               Deployments.decide_run(
                 context.repository,
                 Principal.workflow(grant),
                 context.run.id,
                 "approved"
               )
    end
  end

  describe "workflow grants" do
    setup context do
      environment_fixture(context.repository, context.owner, %{
        "name" => "preview",
        "kind" => "preview"
      })

      environment_fixture(context.repository, context.owner)

      :ok
    end

    test "a grant deploys only its own repository, environment, and source context", context do
      {grant, plaintext} =
        workflow_grant_fixture(context.repository, context.owner, %{"environment" => "preview"})

      assert {:ok, %Principal{kind: :workflow}} =
               Deployments.authenticate_workflow_grant(plaintext)

      attrs = %{
        "environment" => "preview",
        "commit_sha" => commit_sha(),
        "artifact_digest" => artifact_digest(),
        "source_ref" => "refs/heads/main",
        "source_workflow" => "deploy.yml",
        "workflow_run_id" => grant.workflow_run_id,
        "idempotency_key" => "workflow-1234"
      }

      assert {:ok, %Run{state: "queued"}} =
               Deployments.request_deployment(
                 context.repository,
                 Principal.workflow(grant),
                 attrs,
                 commit_store: any_commit()
               )

      assert {:error, {:forbidden, :cross_environment}} =
               Deployments.request_deployment(
                 context.repository,
                 Principal.workflow(grant),
                 %{attrs | "environment" => "production", "idempotency_key" => "widen-env-1234"},
                 commit_store: any_commit()
               )

      assert {:error, {:forbidden, :source_ref_mismatch}} =
               Deployments.request_deployment(
                 context.repository,
                 Principal.workflow(grant),
                 %{attrs | "source_ref" => "refs/tags/v1", "idempotency_key" => "widen-ref-1234"},
                 commit_store: any_commit()
               )

      assert {:error, {:forbidden, :source_workflow_mismatch}} =
               Deployments.request_deployment(
                 context.repository,
                 Principal.workflow(grant),
                 %{
                   attrs
                   | "source_workflow" => "other.yml",
                     "idempotency_key" => "widen-wf-1234"
                 },
                 commit_store: any_commit()
               )

      assert {:error, {:forbidden, :workflow_run_mismatch}} =
               Deployments.request_deployment(
                 context.repository,
                 Principal.workflow(grant),
                 %{
                   attrs
                   | "workflow_run_id" => "other-run",
                     "idempotency_key" => "widen-run-1234"
                 },
                 commit_store: any_commit()
               )
    end

    test "a grant cannot address another repository", context do
      {grant, _plaintext} = workflow_grant_fixture(context.repository, context.owner)

      other_owner = repository_user_fixture("deploy-grant-other")
      other_repository = repository_with_member_fixture(other_owner, %{}, "owner")
      environment_fixture(other_repository, other_owner)

      assert {:error, {:forbidden, :cross_repository}} =
               Deployments.request_deployment(
                 other_repository,
                 Principal.workflow(grant),
                 %{
                   "environment" => "production",
                   "commit_sha" => commit_sha(),
                   "artifact_digest" => artifact_digest(),
                   "source_ref" => "refs/heads/main",
                   "source_workflow" => "deploy.yml",
                   "workflow_run_id" => grant.workflow_run_id,
                   "idempotency_key" => "cross-repo-1234"
                 },
                 commit_store: any_commit()
               )
    end

    test "a revoked grant authenticates nothing", context do
      {grant, plaintext} = workflow_grant_fixture(context.repository, context.owner)

      {:ok, _revoked} =
        Deployments.revoke_workflow_grant(context.repository, context.principal, grant.id)

      assert {:error, :invalid_grant} = Deployments.authenticate_workflow_grant(plaintext)
    end

    test "a grant lifetime is clamped to the maximum", context do
      {grant, _plaintext} =
        workflow_grant_fixture(context.repository, context.owner, %{
          "lifetime_seconds" => 100_000
        })

      assert DateTime.diff(grant.expires_at, DateTime.utc_now()) <= 3_600
    end

    test "a workflow cannot cancel another workflow's run", context do
      {first, _plaintext} = workflow_grant_fixture(context.repository, context.owner)
      {second, _plaintext} = workflow_grant_fixture(context.repository, context.owner)

      {:ok, run} =
        Deployments.request_deployment(
          context.repository,
          Principal.workflow(first),
          %{
            "environment" => "production",
            "commit_sha" => commit_sha(),
            "artifact_digest" => artifact_digest(),
            "source_ref" => "refs/heads/main",
            "source_workflow" => "deploy.yml",
            "workflow_run_id" => first.workflow_run_id,
            "idempotency_key" => "grant-cancel-1234"
          },
          commit_store: any_commit()
        )

      assert {:error, {:forbidden, :cross_repository}} =
               Deployments.cancel_run(context.repository, Principal.workflow(second), run.id)

      assert {:ok, %Run{state: "cancelled"}} =
               Deployments.cancel_run(context.repository, Principal.workflow(first), run.id)
    end
  end

  describe "cancellation and supersession" do
    test "cancelling a queued run reaches a terminal state at once", context do
      environment_fixture(context.repository, context.owner)
      run = run_fixture(context.repository, context.owner)

      assert {:ok, %Run{state: "cancelled"}} =
               Deployments.cancel_run(context.repository, context.principal, run.id)
    end

    test "an optimistic precondition refuses a run that moved", context do
      environment_fixture(context.repository, context.owner)
      run = run_fixture(context.repository, context.owner)

      assert {:error, :precondition_failed} =
               Deployments.cancel_run(context.repository, context.principal, run.id,
                 if_state: "deploying"
               )
    end

    test "a terminal run cannot be cancelled again", context do
      environment_fixture(context.repository, context.owner)
      run = run_fixture(context.repository, context.owner)

      {:ok, cancelled} = Deployments.cancel_run(context.repository, context.principal, run.id)

      assert {:error, {:illegal_transition, "cancelled", "cancelled"}} =
               Deployments.cancel_run(context.repository, context.principal, cancelled.id)
    end

    test "a preview environment supersedes its older waiting runs", context do
      environment_fixture(context.repository, context.owner, %{
        "name" => "preview",
        "kind" => "preview",
        "protection" => %{"concurrency" => "supersede", "required_approvals" => 1}
      })

      older = run_fixture(context.repository, context.owner, %{"environment" => "preview"})
      newer = run_fixture(context.repository, context.owner, %{"environment" => "preview"})

      assert {:ok, %Run{state: "superseded", superseded_by_run_id: superseded_by}} =
               Deployments.fetch_run(context.repository, context.principal, older.id)

      assert superseded_by == newer.id
    end

    test "production does not supersede implicitly", context do
      environment_fixture(context.repository, context.owner, %{
        "protection" => %{"required_approvals" => 1}
      })

      older = run_fixture(context.repository, context.owner)
      _newer = run_fixture(context.repository, context.owner)

      assert {:ok, %Run{state: "waiting_for_approval"}} =
               Deployments.fetch_run(context.repository, context.principal, older.id)
    end
  end

  describe "provider execution" do
    setup context do
      environment_fixture(context.repository, context.owner)
      %{run: run_fixture(context.repository, context.owner)}
    end

    test "one queued run is claimed by exactly one worker", context do
      assert {:ok, claimed} = Deployments.claim_run("worker-a")
      assert claimed.id == context.run.id
      assert claimed.lease_owner == "worker-a"
      assert :empty = Deployments.claim_run("worker-b")
    end

    test "a successful run records a sanitized receipt and no secret values" do
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "succeeded"} = finished} =
               Worker.execute(claimed, "worker-a")

      assert finished.provider_receipt["commit_sha"] == commit_sha()
      refute Map.has_key?(finished.provider_receipt, "secrets")
      assert is_nil(finished.lease_owner)
    end

    test "a duplicate execution never deploys twice", context do
      {:ok, claimed} = Deployments.claim_run("worker-a")
      {:ok, _finished} = Worker.execute(claimed, "worker-a")

      {:ok, receipt} = Fake.receipt(context.run.id)
      assert receipt["run_id"] == context.run.id

      assert {:error, {:illegal_transition, "succeeded", _to}} =
               Worker.execute(%Run{claimed | state: "succeeded"}, "worker-a")
    end

    test "a provider failure never produces a success receipt", context do
      :ok = Fake.program(context.run.id, :fail)
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "provider_rejected"}} =
               Worker.execute(claimed, "worker-a")
    end

    test "an uncertain provider result is an explicitly uncertain failure", context do
      :ok = Fake.program(context.run.id, :uncertain)
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "provider_result_uncertain"}} =
               Worker.execute(claimed, "worker-a")
    end

    test "a provider timeout is uncertain, not successful", context do
      :ok = Fake.program(context.run.id, :hang)
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "provider_result_uncertain"}} =
               Worker.execute(claimed, "worker-a")
    end

    test "authority revoked between queueing and deploying halts the run", context do
      deployer = repository_user_fixture("deploy-losing-access")

      {:ok, _membership} =
        OpenAgents.Repositories.add_member(context.repository, deployer, "contributor")

      _run =
        run_fixture(context.repository, deployer, %{"idempotency_key" => "revoked-access-1234"})

      :ok = OpenAgents.Repositories.remove_member(context.repository, context.owner, deployer.id)

      {:ok, _cancelled} =
        Deployments.cancel_run(context.repository, context.principal, context.run.id)

      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "authority_revoked_not_writable"}} =
               Worker.execute(claimed, "worker-a")
    end

    test "a freeze applied after queueing denies the run before the provider runs", context do
      environment_fixture(context.repository, context.owner, %{
        "protection" => %{"frozen" => true, "freeze_reason" => "incident"}
      })

      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "frozen"}} =
               Worker.execute(claimed, "worker-a")

      assert Fake.receipt(context.run.id) == :error
    end

    test "cancellation requested while deploying is honored after the provider reports",
         context do
      {:ok, claimed} = Deployments.claim_run("worker-a")

      {:ok, deploying} =
        Deployments.transition(claimed, "deploying", Principal.system("worker-a"))

      {:ok, _cancelling} =
        Deployments.cancel_run(context.repository, context.principal, deploying.id)

      assert {:ok, %Run{state: "cancelled"}} =
               Deployments.finish_run(
                 OpenAgents.Repo.get!(Run, deploying.id),
                 "worker-a",
                 {:ok, %{"detail" => "deployed"}}
               )
    end
  end

  describe "recovery" do
    setup context do
      environment_fixture(context.repository, context.owner)
      %{run: run_fixture(context.repository, context.owner)}
    end

    test "a lease abandoned before the provider ran is requeued", context do
      {:ok, claimed} = Deployments.claim_run("worker-a", lease_seconds: 1)
      later = DateTime.add(DateTime.utc_now(), 60, :second)

      assert {:ok, %{requeued: 1, uncertain: 0}} =
               Deployments.reconcile_leases(Principal.system("reconciler"), now: later)

      assert {:ok, %Run{state: "queued", lease_owner: nil}} =
               Deployments.fetch_run(context.repository, context.principal, claimed.id)

      assert {:ok, _reclaimed} = Deployments.claim_run("worker-b")
    end

    test "a lease abandoned while deploying is uncertain, never succeeded", context do
      {:ok, claimed} = Deployments.claim_run("worker-a", lease_seconds: 1)

      {:ok, _deploying} =
        Deployments.transition(claimed, "deploying", Principal.system("worker-a"))

      later = DateTime.add(DateTime.utc_now(), 60, :second)

      assert {:ok, %{requeued: 0, uncertain: 1}} =
               Deployments.reconcile_leases(Principal.system("reconciler"), now: later)

      assert {:ok, %Run{state: "failed", result_reason: "provider_result_uncertain"}} =
               Deployments.fetch_run(context.repository, context.principal, claimed.id)
    end

    test "a worker that lost its lease cannot renew it" do
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, _renewed} = Deployments.renew_lease(claimed, "worker-a")
      assert :error = Deployments.renew_lease(claimed, "worker-b")
    end

    test "only operator or system authority reconciles", context do
      assert {:error, {:forbidden, :not_an_operator}} =
               Deployments.reconcile_leases(context.principal)
    end
  end

  describe "events" do
    setup context do
      environment_fixture(context.repository, context.owner)
      %{run: run_fixture(context.repository, context.owner)}
    end

    test "a run's history is append-only and monotonic", context do
      {:ok, events} = Deployments.list_events(context.repository, context.principal, context.run)

      assert Enum.map(events, & &1.sequence) == Enum.to_list(1..length(events))
      assert hd(events).type == "run_created"
    end

    test "a subscriber sees committed transitions only", context do
      :ok = Deployments.subscribe(context.run)

      {:ok, _cancelled} =
        Deployments.cancel_run(context.repository, context.principal, context.run.id)

      assert_receive {:deployment_event, %{run_id: run_id, state: "cancelled"}}
      assert run_id == context.run.id
    end

    test "event detail redacts credentials", context do
      {:ok, claimed} = Deployments.claim_run("worker-a")

      {:ok, _failed} =
        Deployments.finish_run(claimed, "worker-a", {:error, "Bearer sk-secret-token-value"})

      {:ok, events} = Deployments.list_events(context.repository, context.principal, claimed)
      details = Enum.map(events, & &1.detail)

      refute Enum.any?(details, fn detail ->
               detail |> inspect() |> String.contains?("sk-secret-token-value")
             end)
    end

    test "a provider receipt cannot echo a resolved secret value", _context do
      receipt =
        OpenAgents.Deployments.Provider.sanitize_receipt(
          %{"echo" => "value=super-secret-value"},
          ["super-secret-value"]
        )

      assert receipt["echo"] == "value=[REDACTED_SECRET]"
    end
  end

  describe "secret boundary" do
    test "an execution resolves declared references only, and never persists them", context do
      environment =
        environment_fixture(context.repository, context.owner, %{
          "provider_config" => %{"secret_reference" => "DEPLOY_TOKEN"},
          "secret_references" => ["DEPLOY_TOKEN"]
        })

      variable =
        OpenAgents.Deployments.SecretResolver.Environment.variable_name(
          environment,
          "DEPLOY_TOKEN"
        )

      System.put_env(variable, "resolved-secret-value")
      on_exit(fn -> System.delete_env(variable) end)

      run = run_fixture(context.repository, context.owner)
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "succeeded"} = finished} = Worker.execute(claimed, "worker-a")
      assert finished.provider_receipt["secret_references_resolved"] == "DEPLOY_TOKEN"

      refute finished |> inspect(limit: :infinity) |> String.contains?("resolved-secret-value")
      assert run.id == finished.id
    end

    test "a missing secret fails the run rather than deploying without it", context do
      environment_fixture(context.repository, context.owner, %{
        "provider_config" => %{"secret_reference" => "DEPLOY_TOKEN"},
        "secret_references" => ["DEPLOY_TOKEN"]
      })

      run = run_fixture(context.repository, context.owner)
      {:ok, claimed} = Deployments.claim_run("worker-a")

      assert {:ok, %Run{state: "failed", result_reason: "secret_unavailable"}} =
               Worker.execute(claimed, "worker-a")

      assert Fake.receipt(run.id) == :error
    end

    test "a provider cannot resolve a reference the environment did not declare", context do
      environment =
        environment_fixture(context.repository, context.owner, %{
          "secret_references" => ["DECLARED_TOKEN"]
        })

      assert {:error, {:undeclared_secret_reference, "OTHER_TOKEN"}} =
               OpenAgents.Deployments.SecretResolver.resolve(environment, ["OTHER_TOKEN"])
    end
  end
end