Skip to content

feat: v0.18.6 — infra state persistence + remote backend loader + destroy/status/drift direct paths + bootstrap URL export - #471

Merged
intel352 merged 7 commits into
mainfrom
feat/v0.18.6-infra-holistic
Apr 23, 2026
Merged

intel352 merged 7 commits into
mainfrom
feat/v0.18.6-infra-holistic

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Summary

  • State persistence after apply: applyWithProviderAndStore saves ResourceState for each successfully provisioned resource; delete-action resources are removed from state. Previously state was never written, causing every run to re-create.
  • Remote state backend loader: resolveStateStore supports filesystem and DO Spaces backends. loadCurrentState now delegates to it, enabling Spaces-backed state to be read by plan/apply.
  • Direct-path destroy for infra.* modules: runInfraDestroy dispatches to destroyInfraModules (loads state, calls provider.Destroy, removes state records) instead of requiring a non-existent pipelines.destroy pipeline.
  • Direct-path status + drift for infra.* modules: same dispatch fix for runInfraStatus and runInfraDrift, calling provider.Status / provider.DetectDrift directly on tracked records.
  • Bootstrap Spaces bucket URL export: after creating/confirming the bucket, prints export DO_SPACES_BUCKET=<name> for CI capture and writes the resolved name back to the on-disk config.

Test plan

  • GOWORK=off go test -race -short ./cmd/wfctl/... — all pass
  • GOWORK=off go build ./... — clean
  • go vet ./cmd/wfctl/... — clean
  • gofmt -l ./cmd/wfctl/ — no output

🤖 Generated with Claude Code

intel352 and others added 4 commits April 23, 2026 09:55
…tate loss

Refactors applyWithProvider → applyWithProviderAndStore(ctx, provider,
providerType, specs, current, store). After provider.Apply returns success,
each ResourceOutput is written to the store; save failures log a loud warning
but do not abort the apply. Delete actions trigger store.DeleteResource after
the Apply call.

Also introduces resolveStateStore(cfgFile) which reads the iac.state module
config and instantiates the correct backend (filesystem or Spaces), rewriting
loadCurrentState to delegate to it so that remote backends are supported
beyond the previous filesystem-only path.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…odules

Adds destroyInfraModules, statusInfraModules, and driftInfraModules that load
state from the configured backend, group records by IaCProvider, and dispatch
to provider.Destroy/Status/DetectDrift respectively.

runInfraDestroy, runInfraStatus, and runInfraDrift now dispatch to the direct
path when hasInfraModules() is true, falling back to the legacy pipeline path
for platform.* configs.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
After bootstrapStateBackend creates or confirms a DO Spaces bucket,
prints 'export DO_SPACES_BUCKET=<name>' to stdout for CI capture via
$GITHUB_ENV, and calls writeBucketBackToConfig to bake the resolved
bucket name into the on-disk YAML so downstream wfctl commands can read
state without the env var being set again.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Copilot AI review requested due to automatic review settings April 23, 2026 16:11
…atus/drift

- Extract provider-loop bodies into closures (applyGroup, destroyGroup,
  statusGroup, driftGroup) to fix deferInLoop in all four files
- Switch range-value loops to index loops for rangeValCopy (plan.Actions
  136B, ResourceState 208B) in infra_apply, infra_destroy, infra_status_drift
- Split combined err+len guard in resolveStateStore to satisfy nilerr;
  add //nolint:nilerr on the intentional err-swallow (noop on missing config)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@github-actions

github-actions Bot commented Apr 23, 2026 •

Copy link
Copy Markdown

⏱ Benchmark Results

✅ No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:245: parsing iteration count: invalid syntax
baseline-bench.txt:321540: parsing iteration count: invalid syntax
baseline-bench.txt:646387: parsing iteration count: invalid syntax
baseline-bench.txt:903224: parsing iteration count: invalid syntax
baseline-bench.txt:1204458: parsing iteration count: invalid syntax
baseline-bench.txt:1551586: parsing iteration count: invalid syntax
benchmark-results.txt:245: parsing iteration count: invalid syntax
benchmark-results.txt:431502: parsing iteration count: invalid syntax
benchmark-results.txt:822331: parsing iteration count: invalid syntax
benchmark-results.txt:1231001: parsing iteration count: invalid syntax
benchmark-results.txt:1895427: parsing iteration count: invalid syntax
benchmark-results.txt:2262589: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4              3.137m ± 208%
ComponentLoad-4                    3.610m ±  11%
ComponentExecute-4                 1.957µ ±   0%
PoolContention/workers-1-4         1.092µ ±   4%
PoolContention/workers-2-4         1.092µ ±   2%
PoolContention/workers-4-4         1.095µ ±   1%
PoolContention/workers-8-4         1.100µ ±  12%
PoolContention/workers-16-4        1.124µ ±   3%
ComponentLifecycle-4               3.707m ±   0%
SourceValidation-4                 2.345µ ±   1%
RegistryConcurrent-4               861.5n ±   3%
LoaderLoadFromString-4             3.732m ±   1%
geomean                            17.78µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               2.027Mi ± 0%
ComponentLoad-4                     2.180Mi ± 0%
ComponentExecute-4                  1.203Ki ± 0%
PoolContention/workers-1-4          1.203Ki ± 0%
PoolContention/workers-2-4          1.203Ki ± 0%
PoolContention/workers-4-4          1.203Ki ± 0%
PoolContention/workers-8-4          1.203Ki ± 0%
PoolContention/workers-16-4         1.203Ki ± 0%
ComponentLifecycle-4                2.183Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.182Mi ± 0%
geomean                             15.25Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.68k ± 0%
ComponentLoad-4                      18.02k ± 0%
ComponentExecute-4                    25.00 ± 0%
PoolContention/workers-1-4            25.00 ± 0%
PoolContention/workers-2-4            25.00 ± 0%
PoolContention/workers-4-4            25.00 ± 0%
PoolContention/workers-8-4            25.00 ± 0%
PoolContention/workers-16-4           25.00 ± 0%
ComponentLifecycle-4                 18.07k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               18.06k ± 0%
geomean                               183.3

cpu: AMD EPYC 9V74 80-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                  2.324m ± 46%
ComponentLoad-4                        2.695m ±  0%
ComponentExecute-4                     1.401µ ±  1%
PoolContention/workers-1-4             787.6n ±  3%
PoolContention/workers-2-4             787.7n ±  1%
PoolContention/workers-4-4             786.0n ±  1%
PoolContention/workers-8-4             784.9n ±  1%
PoolContention/workers-16-4            787.6n ±  0%
ComponentLifecycle-4                   2.719m ±  1%
SourceValidation-4                     1.630µ ±  0%
RegistryConcurrent-4                   595.7n ±  4%
LoaderLoadFromString-4                 2.743m ±  1%
geomean                                12.79µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  2.027Mi ± 0%
ComponentLoad-4                        2.180Mi ± 0%
ComponentExecute-4                     1.203Ki ± 0%
PoolContention/workers-1-4             1.203Ki ± 0%
PoolContention/workers-2-4             1.203Ki ± 0%
PoolContention/workers-4-4             1.203Ki ± 0%
PoolContention/workers-8-4             1.203Ki ± 0%
PoolContention/workers-16-4            1.203Ki ± 0%
ComponentLifecycle-4                   2.183Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.182Mi ± 0%
geomean                                15.25Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.68k ± 0%
ComponentLoad-4                         18.02k ± 0%
ComponentExecute-4                       25.00 ± 0%
PoolContention/workers-1-4               25.00 ± 0%
PoolContention/workers-2-4               25.00 ± 0%
PoolContention/workers-4-4               25.00 ± 0%
PoolContention/workers-8-4               25.00 ± 0%
PoolContention/workers-16-4              25.00 ± 0%
ComponentLifecycle-4                    18.07k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  18.06k ± 0%
geomean                                  183.3

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  286.8n ± 0%
CircuitBreakerExecution_Success-4          21.57n ± 0%
CircuitBreakerExecution_Failure-4          65.92n ± 0%
geomean                                    74.15n

                                  │ baseline-bench.txt │
                                  │        B/op        │
CircuitBreakerDetection-4                 144.0 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │
                                  │     allocs/op      │
CircuitBreakerDetection-4                 1.000 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                     229.8n ± 3%
CircuitBreakerExecution_Success-4             17.57n ± 1%
CircuitBreakerExecution_Failure-4             55.20n ± 0%
geomean                                       60.63n

                                  │ benchmark-results.txt │
                                  │         B/op          │
CircuitBreakerDetection-4                    144.0 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

                                  │ benchmark-results.txt │
                                  │       allocs/op       │
CircuitBreakerDetection-4                    1.000 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     867.4n ± 29%
JQTransform_ObjectConstruction-4         1.444µ ±  0%
JQTransform_ArraySelect-4                3.267µ ±  0%
JQTransform_Complex-4                    37.37µ ±  0%
JQTransform_Throughput-4                 1.768µ ±  1%
SSEPublishDelivery-4                     71.11n ±  0%
geomean                                  1.637µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.22Ki ± 0%
JQTransform_Throughput-4               1.984Ki ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │
                                 │     allocs/op      │
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    324.0 ± 0%
JQTransform_Throughput-4                 17.00 ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        627.5n ± 35%
JQTransform_ObjectConstruction-4            1.077µ ±  2%
JQTransform_ArraySelect-4                   2.566µ ±  0%
JQTransform_Complex-4                       31.67µ ±  1%
JQTransform_Throughput-4                    1.327µ ±  1%
SSEPublishDelivery-4                        49.73n ±  1%
geomean                                     1.239µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.22Ki ± 0%
JQTransform_Throughput-4                  1.984Ki ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                 │ benchmark-results.txt │
                                 │       allocs/op       │
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       324.0 ± 0%
JQTransform_Throughput-4                    17.00 ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                   1.106µ ± 10%
SchemaValidation_AllFields-4                1.662µ ±  1%
SchemaValidation_FormatValidation-4         1.609µ ±  2%
SchemaValidation_ManySchemas-4              1.825µ ±  3%
geomean                                     1.524µ

                                    │ baseline-bench.txt │
                                    │        B/op        │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │
                                    │     allocs/op      │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                       836.5n ± 8%
SchemaValidation_AllFields-4                    1.246µ ± 5%
SchemaValidation_FormatValidation-4             1.210µ ± 2%
SchemaValidation_ManySchemas-4                  1.219µ ± 4%
geomean                                         1.113µ

                                    │ benchmark-results.txt │
                                    │         B/op          │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                    │ benchmark-results.txt │
                                    │       allocs/op       │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.200µ ± 11%
EventStoreAppend_SQLite-4                  1.211m ±  4%
GetTimeline_InMemory/events-10-4           13.74µ ±  2%
GetTimeline_InMemory/events-50-4           75.31µ ± 20%
GetTimeline_InMemory/events-100-4          121.2µ ±  0%
GetTimeline_InMemory/events-500-4          623.5µ ±  0%
GetTimeline_InMemory/events-1000-4         1.271m ±  0%
GetTimeline_SQLite/events-10-4             108.4µ ±  2%
GetTimeline_SQLite/events-50-4             247.1µ ±  0%
GetTimeline_SQLite/events-100-4            417.0µ ±  1%
GetTimeline_SQLite/events-500-4            1.763m ±  0%
GetTimeline_SQLite/events-1000-4           3.446m ±  0%
geomean                                    215.1µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  783.0 ± 9%
EventStoreAppend_SQLite-4                  1.985Ki ± 2%
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%
geomean                                    67.30Ki

                                   │ baseline-bench.txt │
                                   │     allocs/op      │
EventStoreAppend_InMemory-4                  7.000 ± 0%
EventStoreAppend_SQLite-4                    53.00 ± 0%
GetTimeline_InMemory/events-10-4             125.0 ± 0%
GetTimeline_InMemory/events-50-4             653.0 ± 0%
GetTimeline_InMemory/events-100-4           1.306k ± 0%
GetTimeline_InMemory/events-500-4           6.514k ± 0%
GetTimeline_InMemory/events-1000-4          13.02k ± 0%
GetTimeline_SQLite/events-10-4               382.0 ± 0%
GetTimeline_SQLite/events-50-4              1.852k ± 0%
GetTimeline_SQLite/events-100-4             3.681k ± 0%
GetTimeline_SQLite/events-500-4             18.54k ± 0%
GetTimeline_SQLite/events-1000-4            37.29k ± 0%
geomean                                     1.162k

cpu: AMD EPYC 9V74 80-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   748.2n ±  9%
EventStoreAppend_SQLite-4                     3.538m ± 87%
GetTimeline_InMemory/events-10-4              8.450µ ± 21%
GetTimeline_InMemory/events-50-4              42.37µ ±  1%
GetTimeline_InMemory/events-100-4             84.53µ ±  0%
GetTimeline_InMemory/events-500-4             432.6µ ±  0%
GetTimeline_InMemory/events-1000-4            877.4µ ±  1%
GetTimeline_SQLite/events-10-4                64.73µ ±  2%
GetTimeline_SQLite/events-50-4                170.3µ ±  2%
GetTimeline_SQLite/events-100-4               298.0µ ±  2%
GetTimeline_SQLite/events-500-4               1.303m ±  0%
GetTimeline_SQLite/events-1000-4              2.546m ±  1%
geomean                                       162.2µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                    865.5 ± 14%
EventStoreAppend_SQLite-4                    1.983Ki ±  4%
GetTimeline_InMemory/events-10-4             7.953Ki ±  0%
GetTimeline_InMemory/events-50-4             46.62Ki ±  0%
GetTimeline_InMemory/events-100-4            94.48Ki ±  0%
GetTimeline_InMemory/events-500-4            472.8Ki ±  0%
GetTimeline_InMemory/events-1000-4           944.3Ki ±  0%
GetTimeline_SQLite/events-10-4               16.74Ki ±  0%
GetTimeline_SQLite/events-50-4               87.14Ki ±  0%
GetTimeline_SQLite/events-100-4              175.4Ki ±  0%
GetTimeline_SQLite/events-500-4              846.1Ki ±  0%
GetTimeline_SQLite/events-1000-4             1.639Mi ±  0%
geomean                                      67.86Ki

                                   │ benchmark-results.txt │
                                   │       allocs/op       │
EventStoreAppend_InMemory-4                     7.000 ± 0%
EventStoreAppend_SQLite-4                       53.00 ± 2%
GetTimeline_InMemory/events-10-4                125.0 ± 0%
GetTimeline_InMemory/events-50-4                653.0 ± 0%
GetTimeline_InMemory/events-100-4              1.306k ± 0%
GetTimeline_InMemory/events-500-4              6.514k ± 0%
GetTimeline_InMemory/events-1000-4             13.02k ± 0%
GetTimeline_SQLite/events-10-4                  382.0 ± 0%
GetTimeline_SQLite/events-50-4                 1.852k ± 0%
GetTimeline_SQLite/events-100-4                3.681k ± 0%
GetTimeline_SQLite/events-500-4                18.54k ± 0%
GetTimeline_SQLite/events-1000-4               37.29k ± 0%
geomean                                        1.162k

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

Comment thread cmd/wfctl/infra_bootstrap.go Outdated
}

return bootstrapDOSpacesBucketFn(ctx, bucket, region, accessKey, secretKey)
if err := bootstrapDOSpacesBucketFn(ctx, bucket, region, accessKey, secretKey); err != nil {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there DO-specific bootstrapping here? This should be a hook system or similar, and the relevant provider bootstrap should load from that hook. DO logic should not be built into wfctl, same for AWS, Azure, etc, as I believe we have a provider plugin pattern for each, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — this is an architectural leak. Refactoring now so bootstrap dispatches through the IaCProvider plugin interface (new method BootstrapStateBackend), with DO Spaces logic moving from wfctl core into workflow-plugin-digitalocean. wfctl will only be responsible for resolving the provider + delegating. See fix commits inbound.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2d407fe. BootstrapStateBackend(ctx, cfg) (*BootstrapResult, error) is now a method on the IaCProvider interface — every cloud provider plugin implements it. All DO-specific S3/AWS SDK code has been removed from wfctl core; bootstrapStateBackend simply finds the first iac.provider module, calls resolveIaCProvider, and delegates. Self-contained backends (filesystem/memory/postgres) remain no-ops in wfctl. DO Spaces implementation will follow in workflow-plugin-digitalocean v0.7.4 (follow-up #31).

intel352 and others added 2 commits April 23, 2026 12:58
…re + follow-up TODOs

bootstrapStateBackend now dispatches by iac.state.backend:
- spaces → bootstrapStateBackendSpaces (DO endpoint URL constructed here)
- s3/gcs/azure → clear not-yet-implemented errors with contribution guidance
- filesystem/memory/postgres/"" → no-op

bootstrapStateBackendSpaces: exports WFCTL_STATE_BUCKET (generic) +
SPACES_BUCKET (backend-specific, no cloud-provider prefix). bootstrapDOSpacesBucket
now accepts caller-supplied endpoint; creds error message genericised; log
message updated to "created spaces state bucket".

resolveStateStore: wires module.PostgresIaCStateStore for backend=postgres;
s3/gcs/azure return clear errors instead of silent noop.

Misc:
- TODO(#28) added to deploy.go hardcoded credential checks
- TODO(#29) added to providerCredentialSubKeys map
- infra import --provider help text no longer lists specific providers
- All bootstrapDOSpacesBucketFn test fakes updated for new endpoint param
- CHANGELOG updated

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Move all cloud-provider-specific bucket-creation logic out of wfctl core
and behind the IaCProvider plugin interface:

- interfaces/iac_provider.go: add BootstrapStateBackend(ctx, cfg)
  (*BootstrapResult, error) to IaCProvider; add BootstrapResult struct
  (Bucket, Region, Endpoint, EnvVars)
- infra_bootstrap.go: remove all DO/AWS SDK imports and S3-specific code;
  bootstrapStateBackend now finds the first iac.provider module, calls
  resolveIaCProvider, then delegates to provider.BootstrapStateBackend;
  self-contained backends (filesystem/memory/postgres/"") remain no-ops
- deploy_providers.go: wire BootstrapStateBackend on remoteIaCProvider
  via InvokeService + anyToStruct, consistent with rest of bridge
- All IaCProvider test stubs: add BootstrapStateBackend(nil, nil) stub
- Delete infra_bootstrap_bucket_test.go: DO-specific S3 tests move to
  DO plugin (follow-up #31, workflow-plugin-digitalocean v0.7.4)
- Rewrite infra_bootstrap_env_test.go + infra_bootstrap_url_export_test.go:
  replace bootstrapDOSpacesBucketFn overrides with resolveIaCProvider
  overrides using envBootstrapProvider / urlBootstrapProvider fakes
- Add infra_bootstrap_provider_test.go: TestBootstrapStateBackend_DispatchesToProvider
  (full round-trip), SelfContainedBackendsSkipped, NoProviderModuleErrors

Addresses review comment #3132352899 (intel352): DO-specific bootstrap
should not live in wfctl core.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@intel352
intel352 merged commit 4ec75b7 into main Apr 23, 2026
18 checks passed
@intel352
intel352 deleted the feat/v0.18.6-infra-holistic branch April 23, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant