CGOA — GitOps Certified Associate
Before approving an empty target
In one line
An empty target may be an intentional retirement or a wrongly generated result. Before you turn the protection off, you must check the current commit and the actual scope of deletion.
Why this was needed
After you cleaned up the per-environment directories, the deployment screen became OutOfSync. The last operation says Succeeded. One person says reconciliation is slow so let's wait, and another wants to change the setting, saying that turning on allowEmpty will make it green. Neither has yet checked what is empty or which operation succeeded. If you approve a wrongly generated result, automation can perform an unintended full deletion.
Before building this unit, an experiment was run with a small ConfigMap on a real Argo CD v3.5.2. When an empty target was created, the object remained and a SyncError appeared, yet operationState.phase was Succeeded. On checking, that success was the record of the earlier commit that had created the object, not the current empty-target commit. A verification that looks only at the success string goes beyond missing a failure: it could report as successful a deletion that the protection was blocking.
How it works
Automated prune has a protection that blocks a mass deletion when there are no target resources at all. If you set allowEmpty to true, you can turn that protection off. This is not a repair button for quickly clearing an error but an operating decision to allow an empty state. The lab entrusts the second Application with only one disposable ConfigMap. The retained and anchor of the first Application must keep the same UID and data until the experiment ends. It verifies the boundary while keeping the size of the approval target small.
The first distinction is between a generation failure and a valid empty result. If you specify a source.path that does not exist, the stage of reading the manifests itself may fail. You must not use this as evidence of the empty-target protection. In this repository you keep the empty directory and change resources.json to a valid empty List like the following.
{"apiVersion":"v1","kind":"List","items":[]}
The second distinction is between the commit you compared and the operation you ran. status.sync.revision is the coordinate of the desired state you compared now, and status.operationState.syncResult.revision is the coordinate to which that operation's result belongs. If the two values differ, you cannot read the Succeeded of an old operation as an execution success for the current commit. You must look at conditions too. In this environment the rejection message was auto-sync will wipe out all resources, and the first probe written guessed that the wording would contain empty, and so missed the real protection. That failure was also left in the verification record. Because the wording can change with the version, the student environment pins the version, and apart from a single message, it checks together the empty target, the current revision, the policy, and the preserved UID.
| Observation | Git target | Actual disposable | Policy and meaning |
|---|---|---|---|
| Baseline | One object | Baseline UID | allowEmpty=false |
| Empty-target observation | 0 objects | Same UID | Automatic full deletion is rejected |
| Allowed after review | 0 objects, same commit | Gone | Actually deleted with allowEmpty=true |
| Git restoration | One object, new commit | New UID | Default protection restored to false, object recreated |
Confirm that even when only the policy changes on the same commit, the actual object can disappear. The claim that you reviewed only the Git diff does not mean you also reviewed the change to the Application policy. The record of change approval must leave not only the Git coordinates but also which Application, which policy, and which resource list you looked at when you decided.
What it looks like in the field
There are cases, such as retiring per-branch test environments, where an empty target can be legitimate. Even so, you must check that you did not treat a rendering failure as an empty result, that the target environment really is to be retired, and that there is no data that must be kept. Conversely, if you intend to keep the environment but the result is empty, restoring the filter condition or the path selection first fits the intent better. If you make getting a green light itself the completion condition, even a state where all resources have vanished and so there is no longer any difference looks like a success.
When writing the report, answer the following questions in order. Did rendering of the current commit succeed? Is the reason the result is empty an intentional retirement? What exactly are the deletion targets this Application owns? After approval, did only the expected targets disappear? If restoration is needed, what can be recovered, and from where, for the object declaration and for the data respectively?
The last question is left deliberately incomplete in this lab. If you recreate the ConfigMap from Git, you can put in the same data, but the UID is new. The contents of a database or volume do not come back with it. Do not write that this experiment verified a backup. The recoverability of real data must be proven through a separate backup and restore test.
What you will do in the next lab
preview-empty creates the empty target and first saves the observation in which the protection worked. At this point disposable must still remain. After reading the current commit, the previous operation's commit, and the target UID in guard-7.json, you explicitly allow it. In the next step you restore the Git definition and the default protection and confirm the new UID. An already completed step does not repeat the deletion even if you re-run it, and grading only reads the actual state. If the change record is cut off at pending, it does not guess that it was completed and preserves the material. It is designed to avoid the habit of unconditionally performing the same deletion again just to get a new observation.
Official documentation
- Argo CD automated sync: Check the relationship between automated prune and allowEmpty.
- Kubernetes ConfigMap: Check what the experiment object holds and what it does not.