Documentation
¶
Overview ¶
Package verify runs a full fire/restore cycle and checks the result by reading the account back, twice.
WHY THIS EXISTS: the planner, the state machine and the ordering are unit-tested, and discovery has run against live endpoints. But nothing had ever run with credentials that work, so no fire and no restore had ever executed. Unit tests cannot catch an API contract mismatch — a field that means something other than what was assumed, a call that succeeds and does nothing, a restore that puts back a value the API silently coerces — and that is the failure this is guarding against.
THE SECOND READ IS THE WHOLE POINT. `fire` returning no error means the API accepted the calls. It does not mean the desired-count is actually zero, the listener actually blocked, or the concurrency actually pinned. So every action is checked by re-discovering the account and comparing what came back against what the action claimed to do — and after `restore`, against what was there before anything was touched.
discover ──► plan ──► fire ──► DISCOVER AGAIN ──► did each action land?
│ │
└── pre-state ◄──────── DISCOVER AGAIN ◄── restore ◄──┘
│
is everything back?
The output is deliberately counts and kinds. A verification run happens in somebody's account, and the summary is meant to be pasted into an issue: ARNs, account ids, instance names and DNS names must not travel with it. Redact() is not a formatting nicety, it is the thing that makes the report postable.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var AllKinds = []model.Kind{ model.KindALBListener, model.KindLambda, model.KindECSService, model.KindASG, model.KindEC2Instance, model.KindNATGateway, model.KindRDSInstance, model.KindRDSCluster, model.KindEKSNodegroup, model.KindCloudFront, model.KindAPIGatewayStage, }
AllKinds is what a scratch account has to hold for a run to mean anything. Kept here rather than derived from what was found, so a kind that discovery silently stopped returning shows up as unexercised rather than vanishing.
Functions ¶
This section is empty.
Types ¶
type Discoverer ¶
Discoverer reads the account. An interface so the whole cycle runs against an in-memory account in the tests: a harness whose own logic is unverified would be the worst possible thing to trust a fire/restore report to.
type Finding ¶
type Finding struct {
Stage string // "fire" or "restore"
Kind model.Kind
Ref string // "ecs-service#2" — stable within one report, meaningless outside it
Want string
Got string
Detail string
}
Finding is one thing that did not match. Every field here is safe to post: the resource is named by kind and by an opaque index, never by ARN.
type Options ¶
type Options struct {
Settle time.Duration
Poll time.Duration
Now func() time.Time
SkipFire bool // plan and report only; nothing is changed
Region string
AccountID string
}
Settle is how long to wait after a change before reading it back. AWS is eventually consistent on most of these — an ECS service reports its old desired count for a moment, an ASG takes a beat to reflect a scale — and a verifier that read too early would report a divergence that is only its own impatience.
type Report ¶
type Report struct {
StartedAt time.Time
Duration time.Duration
// Discovered counts every resource found, by kind. A kind with zero here
// is a kind this run did NOT exercise, which is as important as the ones
// it did — the acceptance criterion is "at least one of each".
Discovered map[model.Kind]int
Planned map[model.Kind]int
Refused map[model.Kind]int
FireChanged int
FireFailed int
FireVerified int
RestoreOK int
RestoreFailed int
Findings []Finding
// Unexercised names the kinds the scratch account had none of. Listed
// explicitly, because "no findings" over a kind that was never present is
// not evidence of anything.
Unexercised []model.Kind
Errors []string
}
Report is what gets pasted into the issue.
func Run ¶
func Run( ctx context.Context, d Discoverer, ex engine.Executor, st state.Store, pol policy.Policy, opt Options, ) (*Report, error)
Run does the cycle. It returns a report even on error: a run that fell over halfway is exactly the one whose partial findings are worth reading.
func (*Report) OK ¶
OK is whether the run is evidence the tool works: every action landed, every resource came back, and nothing diverged. A run with unexercised kinds is still OK — it is just narrower, and Text() says which.
func (*Report) Text ¶
Text renders the report as something that can be pasted into an issue.
The redaction is structural, not a filter: nothing in the Report type holds an ARN, an account id or a resource name in the first place, so there is nothing here that could accidentally print one. That is deliberate — a formatter that had access to the identifiers and chose not to print them would be one edit away from leaking an account inventory into a public tracker.