Documentation
¶
Overview ¶
Package gate implements pre-apply DNS policy enforcement. Operators configure a TXT policy at `_workflow-dns-policy.<zone>` declaring which owners may upsert which (name, type) tuples; the Gate reads that policy at apply time and denies actions that the policy does not permit.
Relocated from workflow-plugin-infra/internal/dnsgate. Adapted to dispatch via interfaces.ResourceDriver.Read (not dnspolicy.Adapter) so the same gate logic works against any DNS provider that implements the strict-contract ResourceDriver interface — not just providers carrying the legacy libdns surface.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Gate ¶
func Gate(ctx context.Context, reader policy.DNSPolicyReader, zone, name, recordType, owner string) error
Gate is the uncached entry point (one GetTXT per call). Use this for one-off invocations (CLI commands, integration tests). For step handlers or apply loops processing many records in one go, use NewCachingGate + Check so the policy TXT is read at most once per zone.
func PolicyName ¶
PolicyName returns the TXT name where policy lives for a zone — the same convention enforced by the parser side (workflow/dns/policy.Parse expects records named `_workflow-dns-policy.<zone>`).
Types ¶
type CachingGate ¶
type CachingGate struct {
// contains filtered or unexported fields
}
CachingGate is a Gate-call wrapper with per-zone caching. One per wfctl apply invocation; releases at end of invocation (no TTL). Use this when an apply touches multiple records under the same zone — the dns-policy TXT is fetched + parsed exactly once per zone instead of once per record. Mirrors the v1 dnsgate.CachingGate pattern.
func (*CachingGate) Check ¶
func (g *CachingGate) Check(ctx context.Context, reader policy.DNSPolicyReader, zone, name, recordType, owner string) error
Check is the cached entry point — single GetTXT per zone per Gate. Returns nil when (zone, name, recordType, owner) is permitted; non-nil when the policy denies the action. Fails closed: a missing policy TXT (zero policy entries after parse) returns an error rather than allowing.
Reader is the policy.DNSPolicyReader interface — either a libdns adapter (legacy) or a *DriverReader (wfctl-driven, this package). The narrow 2-method interface means new transports can be added without touching the gate logic.
type DriverReader ¶
type DriverReader struct {
// Driver is the resolved ResourceDriver for resource type "infra.dns".
// Caller is responsible for getting the right driver (via
// IaCProvider.ResourceDriver("infra.dns")) before constructing the
// reader — keeps this adapter's concerns narrow.
Driver interfaces.ResourceDriver
// Zone is the FQDN of the zone whose policy is being read. Used as
// ResourceRef.ProviderID — the DNS provider plugins (DO, CF, NC,
// Hover) all accept zone-name-as-ID for the infra.dns resource type.
Zone string
}
DriverReader adapts an interfaces.ResourceDriver to the full policy.DNSPolicyReader interface so the Gate can read TXT records AND the dns-policy mutating commands (set / transfer-ownership) can write them — all via the strict-contract driver path (no libdns dependency).
GetTXT scans Outputs["records"] for TXT records matching the given name. UpsertTXT issues a Driver.Update against a synthesized ResourceSpec whose records list replaces all TXT entries at the target name. Both halves are scoped narrowly to the policy-TXT use case; the general DNS-record CRUD surface is `wfctl infra apply`.
func (*DriverReader) GetTXT ¶
GetTXT implements policy.DNSPolicyReader. Reads the zone via Driver.Read, then scans Outputs["records"] for TXT records whose name matches the requested policy name. Returns an empty (nil) slice when the zone has no matching TXT records — the caller (Gate.Check) handles the "no policy" case by failing closed.
Tolerates both `[]map[string]any` and `[]any` (with element-wise type-assertion) for the Outputs["records"] entry — different provider plugins surface the records slice with slightly different concrete types depending on whether the value passed through a structpb roundtrip or stayed Go-native within the same process. Either shape works.
func (*DriverReader) UpsertTXT ¶
UpsertTXT implements the write half of policy.DNSPolicyReader so DriverReader satisfies the full interface used by the wfctl dns-policy mutating commands AND can be passed to CachingGate.Check (which takes a DNSPolicyReader, not a narrower Reader sub-interface).
Strategy: Read the current zone via Driver.Read, rewrite the records slice replacing all TXT entries at `name` with the supplied values (one TXT RR per value), then call Driver.Update with a synthesized ResourceSpec carrying the new records list.
Limitations: the synthesized ResourceSpec carries only `domain` + `records` fields. Providers requiring additional zone-level config on Update (e.g. CF "type" / "settings") may reject. The narrow scope is intentional — this adapter exists to manage the policy TXT specifically, not to be a general DNS-record CRUD surface (the `wfctl infra apply` path covers general record CRUD via config-declared records).