Files
certctl/internal/connector/target/iis/validate_only.go
T
shankar0123 36d79cd1ff feat(f5,iis): explicit ValidateOnly + leverage existing transactional rollback
Phase 8 of the deploy-hardening I master bundle. F5 + IIS already
have transactional / explicit-backup-restore rollback semantics
in their DeployCertificate paths. Phase 8 adds the explicit
ValidateOnly dry-run probe that operators use to preview a deploy
without touching the live cert.

F5 (validate_only.go):
- ValidateOnly probes the iControl REST API via Authenticate.
  Cheap (no F5 transaction created) + cached after first success.
  Failure surfaces as a wrapped error so operators see the actual
  cause (auth provider down, invalid creds, BIG-IP unreachable,
  etc.). nil client returns ErrValidateOnlyNotSupported.
- A true cert-bind dry-run requires F5's no-commit transaction
  mode (v17.5+); V3-Pro can add per-version dispatch. V2 ships
  the reachability probe as the load-bearing safety check.
- 5 new tests in validate_only_test.go covering: auth-success,
  auth-fail wrapped, nil-client sentinel, error-message contains
  BIG-IP context, recoverable auth-fail surfaces provider info.

IIS (validate_only.go):
- ValidateOnly runs `Get-WebSite -Name <SiteName>` via the
  injected PowerShellExecutor. Confirms the IIS PS module is
  loaded AND the site exists AND the agent has admin privileges.
  Failure here surfaces the actual PowerShell stderr (site not
  found / module missing / access denied).
- A true cert-bind dry-run would need IIS to expose a no-commit
  New-WebBinding (it doesn't); V3-Pro can extend with a
  temp-install + immediate-remove. V2 ships the permission +
  module probe as the load-bearing check.
- 5 new tests in validate_only_test.go covering: get-website
  succeeds, get-website fails, nil-executor sentinel, site-name
  quoting (handles spaces in 'Default Web Site'), output-context
  in error.

Smoke test connectorsAtPhase3 list shrunk from 10 to 7 entries
(f5 + iis + postfix removed). Caddy stays in (file-mode returns
sentinel; api-mode is real-impl). Envoy + Traefik stay in (no
validate-with-target command exists for either). javakeystore +
k8ssecret + ssh + wincertstore stay in pending Phase 9.

Coverage: F5 holds at ≥85%; IIS holds at ≥85%. Race detector
clean. golangci-lint v2.11.4 clean.

Phase 9 next: SSH + WinCertStore + JavaKeystore + K8s — the
non-file-server connectors.
2026-04-30 15:16:11 +00:00

41 lines
1.6 KiB
Go

package iis
import (
"context"
"fmt"
"github.com/shankar0123/certctl/internal/connector/target"
)
// ValidateOnly — Phase 8 of the deploy-hardening I master bundle.
// IIS already has explicit pre-deploy backup + post-rollback
// re-import semantics in DeployCertificate. Phase 8 adds an
// explicit dry-run via a PowerShell health probe: if the agent
// can run a `Get-WebSite` cmdlet, the IIS PowerShell module is
// loaded and the agent has the right permissions; ValidateOnly
// returns nil. Otherwise it returns the wrapped script error so
// operators can preview a deploy without touching the live cert
// store.
//
// Note: a true cert-bind dry-run would require IIS to expose a
// no-commit `New-WebBinding` mode (it does not). For V2 the
// permission + module probe is the load-bearing safety check.
// V3-Pro can extend this with a temporary cert install + immediate
// remove.
func (c *Connector) ValidateOnly(ctx context.Context, request target.DeploymentRequest) error {
if c.executor == nil {
return target.ErrValidateOnlyNotSupported
}
// Probe `Get-WebSite -Name <SiteName>` to confirm the IIS
// PowerShell module is loaded AND the configured site exists.
// Failure here means the agent isn't on a Windows host with
// IIS installed, the site name is wrong, or the agent is
// running as a user without IIS administration privileges.
script := fmt.Sprintf(`Get-WebSite -Name %q | Select-Object -ExpandProperty Name`, c.config.SiteName)
out, err := c.executor.Execute(ctx, script)
if err != nil {
return fmt.Errorf("IIS ValidateOnly: %w (output: %s)", err, out)
}
return nil
}