handler

package
v0.64.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 29, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package handler hosts the infra.admin handler library — the shared business logic dispatched by both the host-side infra.admin workflow module's HTTP routes (T15) and the wfctl `infra admin *` CLI subcommands (T19-T20). Functions are pure: they take their dependencies as parameters (state store, providers, catalog) and return typed adminpb outputs. The HTTP transport + audit logging happens at the module layer; the CLI transport happens at wfctl.

Design: docs/plans/2026-05-27-infra-admin-dynamic-design.md §Handler library Plan: docs/plans/2026-05-27-infra-admin-dynamic.md (Tasks 5 + 6)

Authz contract (this file): every typed input MUST carry an AdminAuthzEvidence whose authz_checked AND authz_allowed are both true. The host module attaches admin-auth middleware on every registered route; the middleware sets the evidence after running authz.Casbin (or whatever the configured authz module is). If the evidence is missing or either bit is false, the handler refuses the request via the Output.error field (NOT a Go-level error, so HTTP transport returns 200 OK with a typed payload that consumers must inspect for non-empty error per the proto tag-100 discriminator).

Default-deny semantics: handler refuses unless BOTH bits prove the host auth pipeline ran AND approved. A missing evidence means the caller bypassed admin auth middleware — likely a wiring bug — and must be refused for safety per design §Authz row.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateConfig

GenerateConfig implements InfraAdminService.GenerateConfig by type-coercing the form-builder's field_values map against the FieldSpecCatalog Kind dispatch, assembling a module config map, and yaml.Marshal-ing the result. Output is a single module entry (name + type + config) the user pastes under their existing `modules:` block. Per plan §Task 6.

**Strict-contract invariant**: never fmt.Sprintf user input into YAML. All values flow through yaml.Marshal of a typed struct or map. TestGenerateConfig_NoFmtSprintfUserInput pins this against regression.

Array encoding contract (cross-task, locked 2026-05-27): array_string + array_object field values arrive JSON-encoded (e.g. `field_values["ingress"] = "[\"rule a\", \"rule b, c\"]"`) so values containing commas survive the wire. Handler decodes via json.Unmarshal. Defensive fallback: a value that doesn't parse as a JSON array is wrapped into a one-element slice so a malformed UI submission doesn't crash the server. See TestGenerateConfig_ArrayValuesJSONDecoded + TestGenerateConfig_PlainStringNotJSONDecoded.

Per design §Authz: default-deny via the shared authz guard.

func GetResource

GetResource implements InfraAdminService.GetResource by reading the named ResourceState from the host's iac.state backend and projecting it into an AdminResourceDetail. AppliedConfig is JSON-encoded into applied_config_json verbatim; Outputs are MASKED via secrets.MaskSensitiveOutputs against secrets.DefaultSensitiveKeys() and then JSON-encoded into outputs_json. The masked-key names are surfaced in sensitive_outputs_redacted so the UI can render a "redacted" affordance per design §Secret redaction:

"GetResource.outputs_json redacts keys matching
 secrets.DefaultSensitiveKeys()."

Per design §Authz row: default-deny when evidence is missing or either authz_checked / authz_allowed is false; refusal surfaces via Output.error rather than a Go-level error.

Not-found surfaces via Output.error too — the design treats missing resources as a non-exceptional condition the UI must handle (e.g. a stale URL after a destroy).

func ListProviders

func ListProviders(
	ctx context.Context,
	providers map[string]interfaces.IaCProvider,
	providerTypeByModule map[string]string,
	fieldCat *catalog.FieldSpecCatalog,
	regionCat *catalog.RegionCatalog,
	engineCat *catalog.EngineCatalog,
	in *adminpb.AdminListProvidersInput,
) (*adminpb.AdminListProvidersOutput, error)

ListProviders implements InfraAdminService.ListProviders by walking the provided `providers` map (keyed by host YAML module name) and emitting one AdminProviderSummary per entry. The summary carries the YAML-config provider_type string from the caller-supplied providerTypeByModule map (NOT provider.Name() — see invariant below), the catalogued region + engine lists for that provider type, and the full catalog type list as supported_types.

**provider_type MUST come from the YAML config string, not provider.Name()** — per spec-reviewer T6 F1 (commit 1ea231fdd) + design cycle-5/6 backports:

  • interfaces.IaCProvider.Name() returns the plugin's DISPLAY name (e.g. "DigitalOcean Provider"). This is operator-facing decoration, not a stable identifier.
  • The YAML-config provider: field (e.g. "digitalocean") is the stable identifier the region + engine catalogs key against.
  • The host module (T15) reads each iac.provider module's config at Init time and populates providerTypeByModule keyed by module-name → provider-type-string.
  • If providerTypeByModule[modName] is missing (e.g. a stale module loaded without re-Init), provider_type stays empty and SupportedRegions + SupportedEngines come back empty — UI degrades gracefully rather than rendering wrong dropdowns.

Signature deviation from design §Handler library (informational — not blocking): the design listed

ListProviders(ctx, providers, regionCat, in)

The proto's AdminProviderSummary requires supported_engines + supported_types (so fieldCat + engineCat are needed) AND the F1 fix requires providerTypeByModule. Final shape is 7 params; design line 233 was underspecified.

regions_source is the literal "local-catalog" per design §FieldSpec Catalog so consumers can distinguish v1's local lookup from a future v1.1 IaCProviderRegionLister gRPC service.

Per design §Authz: default-deny via the shared authz guard.

func ListResourceTypes

ListResourceTypes implements InfraAdminService.ListResourceTypes by walking the FieldSpecCatalog and emitting one AdminResourceTypeMetadata per registered type. Each metadata entry carries the catalog's full FieldSpec list so the new-resource form-builder UI can render the right inputs without an extra RPC per type. Per plan §Task 6 + design §Handler library.

The providers parameter is reserved for symmetry with the other handler functions; v1 of this endpoint does not filter types by live providers (the FieldSpecCatalog is the authoritative type list and assumes every registered type is supportable by every known provider — see TestListProviders_PopulatesRegionsAndEngines AndTypes for the cross-task assumption).

Per design §Authz: default-deny via the shared authz guard.

func ListResources

ListResources implements InfraAdminService.ListResources by reading every ResourceState from the host's iac.state backend, applying the type / provider / app-context filters from the input, and returning AdminResourceSummary rows (no per-resource secrets — outputs are intentionally absent from the list view; the detail view uses GetResource).

Per design §Handler library + plan §Task 5: the function takes `providers` + `catalog` as parameters so the host module and CLI callers can share one dispatch. v1 of this list endpoint does not consult providers or catalog directly — every populated field on AdminResourceSummary derives from the ResourceState itself — but the parameters are preserved in the signature for symmetry with ListResourceTypes / GenerateConfig and to keep the dispatch shape stable when T6 / future enhancements need to cross-check against the live providers map (e.g. dropping resources whose state.ProviderRef no longer matches a registered module).

Per design §Authz row: default-deny when evidence is missing or either authz_checked / authz_allowed is false; refusal surfaces via Output.error rather than a Go-level error so the HTTP transport returns 200 OK with the typed payload (consumers sniff for non-empty error per the proto tag-100 discriminator).

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL