Skip to content

feat(wfctl): interactive + non-interactive secrets setup wizard (PR2/7)#801

Merged
intel352 merged 8 commits into
mainfrom
feat/wfctl-secrets-wizard
May 30, 2026
Merged

feat(wfctl): interactive + non-interactive secrets setup wizard (PR2/7)#801
intel352 merged 8 commits into
mainfrom
feat/wfctl-secrets-wizard

Conversation

@intel352
Copy link
Copy Markdown
Contributor

What

PR2 of the wfctl secrets wizard + smart CI cascade (design+plan in workspace:docs/plans/2026-05-30-wfctl-secrets-wizard-and-smart-ci{-design,}.md, scope-locked). Builds the store-aware secrets wizard on PR1's metadata/adapter foundation.

Tasks (6–10)

  • cmd/wfctl/internal/prompt — reusable bubbletea/v2 widgets: Select/MultiSelect/Input(masked)/Confirm. Each returns ErrNotInteractive (never hangs) when stdin isn't a TTY. (+charm.land/bubbles/v2.)
  • Pure setup engine — selector/valuer injection, structured {Set,Skipped,Failed} report; one engine drives both front-ends and both secrets setup and secrets setup --plugin.
  • Interactive wizard (TTY): resolves the store (--store > secrets.defaultStore > single store > prompt to pick > error), checks store access (✓/✗, redacted), lists each declared secret with ✓ set · updated Nd ago / ✗ unset and multi-select which to set (unset pre-selected), masked input for sensitive, confirm before write.
  • Non-interactive (agents/CI; auto when stdin not a TTY): value sources --from-env (recommended) / stdin KEY=VALUE / --secret NAME=VALUE (help warns argv leak); selectors --all / --only / --skip-existing; back-compat --scope/--org/--visibility/--token-env. Missing value → error names the secret, never hangs.
  • Audit — append-only ${XDG_STATE_HOME:-~/.local/state}/wfctl/plugins/wfctl/secrets-audit.jsonl (name/store/scope/ts; never the value).

Review findings fixed (adversarial + code review)

  • Critical: interactive path now surfaces ErrNotInteractive regardless of engine return (was reporting "N failed" instead of falling back).
  • Important: --plugin non-TTY path no longer reaches Fscanln(os.Stdin)proven no-hang on an open pipe; --all flag added; binary-level no-hang regression test TestSecretsSetupNonTTYDoesNotHang added.

Verification

  • GOWORK=off go test ./cmd/wfctl/ ./cmd/wfctl/internal/prompt/ ./secrets/ → all ok; golangci-lint0 issues.
  • Manual non-TTY smokes: main path exits promptly naming the missing secret; --plugin open-pipe returns in 0s (no hang).

Notes

  • Secret values never logged/echoed/audited; masked TUI input.
  • Copilot review not requested (service down per operator).

🤖 Generated with Claude Code

intel352 and others added 8 commits May 30, 2026 16:31
…put/Confirm)

Adds cmd/wfctl/internal/prompt with five files:
- prompt.go: ErrNotInteractive sentinel + Item type + isTTY helper
- select.go: single-choice list via bubbletea model
- multiselect.go: multi-choice list with space-to-toggle
- input.go: text input using bubbles/v2 textinput (EchoPassword when masked)
- confirm.go: y/n question with configurable default
- prompt_test.go: all constructors return ErrNotInteractive in non-TTY env

Adds charm.land/bubbles/v2 v2.0.0 to go.mod (pairs with bubbletea/v2 v2.0.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…red report)

Adds cmd/wfctl/secrets_setup_engine.go: generic runSetupEngine[D] that
accepts an injected selector (which declared secrets to set), valuer
(where to get the value), and audit callback.

- Queries per-secret Check() status before calling selector.
- Selector-excluded secrets go to report.Skipped.
- Valuer returning provided=false skips without error.
- Set errors go to report.Failed; stopOnErr=true returns on first failure.
- audit callback is NEVER passed the secret value.

Full table of test cases in secrets_setup_engine_test.go with engineTestProvider
(in-memory fake SecretsProvider, distinct from existing fakeSecretsProvider).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y/--skip-existing)

- secrets_setup_noninteractive.go: nonInteractiveSetupArgs struct +
  runSecretsSetupNonInteractive/Ctx: loads config, resolves store, builds
  selector (--only/--skip-existing) + valuer (--from-env > stdin-KV > --secret
  literals), routes through runSetupEngine, prints summary. Never logs values.
- secrets_setup.go: adds --non-interactive, --from-env, --secret (repeatable),
  --only, --skip-existing, --store flags; auto-routes to non-interactive path
  when stdin is not a TTY; interactive path gains masked input for sensitive
  names and --store override.
- infra_secrets.go: adds 'file' provider case to resolveSecretsProvider
  (NewFileProvider, creates dir if missing).
- secrets_setup_noninteractive_test.go: --from-env reads $NAME; --only
  restricts; --secret B=v overrides; --skip-existing skips set secrets;
  missing value → named error (no hang); provider receives exactly the
  expected Sets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- secrets_audit.go: writeSecretsAuditRecord appends a JSONL line to
  ${XDG_STATE_HOME:-~/.local/state}/wfctl/plugins/wfctl/secrets-audit.jsonl.
  Fields: {ts, secret_name, store, scope, actor}. Value is NEVER written.
  resolveSetupStoreName implements 5-priority store resolution:
    1. --store flag  2. defaultStore  3. exactly-one secretStores entry
    4. interactive prompt (returns ""/nil)  5. error (non-interactive)
- secrets_audit_test.go: (a) audit table — single JSONL line written,
  fields present, forbidden value absent, appends on second write.
  (b) store-resolver table — all 5 cases.
- secrets_setup_noninteractive.go: wires writeSecretsAuditRecord after
  each successful Set (best-effort, error discarded); uses
  resolveSetupStoreName instead of manual priority chain.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When --from-env is set and $NAME is not in the environment, treat the
secret as "not provided" (skip) rather than a hard error. This matches
CI usage where only a subset of secrets are injected per job. Hard error
is preserved for the case where no value source at all is configured
(no --from-env, no --secret, no stdin KEY=VALUE).

Caught by Task 10 runtime-launch-validation (step 3: --skip-existing
with --from-env was failing on B because $B wasn't set).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + unused field)

- prompt/{confirm,input,multiselect,select}.go: rewrite single-case type
  switch to type assertion if-statement per gocritic singleCaseSwitch.
- secrets_setup_noninteractive.go: remove unused 'all bool' field from
  nonInteractiveSetupArgs (the --all selector is the default when no
  --only/--skip-existing flags are set).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…k + masked input)

Replaces the legacy buffered-reader interactive loop in runSecretsSetup with
a bubbletea-backed wizard that reuses the SAME runSetupEngine as the
non-interactive path (only the selector/valuer differ).

secrets_setup_interactive.go (new):
- runSecretsSetupInteractive: resolves the store (prompt.Select over
  secretStores keys + builtin provider types env/github/vault/aws/keychain/file
  when unresolved), prints a redacted store-access line via the concrete
  secretsProviderAdapter.checkAccess, queries per-entry status, offers
  prompt.MultiSelect (rows: "NAME ✓ set · updated 3d ago" / "NAME ✗ unset",
  unset preselected), prompt.Confirm summary, then runs the engine with a
  selection-backed selector + masked prompt.Input valuer + shared audit.
- Pure helpers (unit-tested): storePickOptions, formatStatusLabel,
  formatRotatedAge, buildMultiSelectItems, queryDeclStatuses,
  printStoreAccessLine, redactAccessError.

secrets_setup.go:
- routes to the wizard on a TTY; non-interactive (--non-interactive,
  --auto-gen-keys, or non-TTY stdin) keeps the engine-backed flag path.
- if the wizard hits prompt.ErrNotInteractive mid-flow it falls back to the
  non-interactive path (never hangs).
- --auto-gen-keys now implies non-interactive and generates values via the
  non-interactive valuer.

secrets_setup_plugin.go:
- runSecretsSetupPluginWithIO now drives the SAME engine: GitHub provider
  wrapped in secretsProviderAdapter, prompt.Input valuer on a TTY (masked for
  sensitive) / promptOne reader valuer for piped/test input, audit per Set.
- buildSecretWriter returns secrets.Provider (was scopedWriter) so it can be
  adapted; scopedWriter removed.

secrets_setup_noninteractive.go: valuer gains --auto-gen-keys branch.

Tests: interactive wiring helpers + --auto-gen-keys non-interactive path.
Existing plugin tests (piped reader) still pass unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…all + binary test; minors

CRITICAL: interactive setup now checks captured promptErr BEFORE the engine's
err. With stopOnErr=false the engine returns (report, nil) even when a
prompt.Input valuer reported ErrNotInteractive (e.g. stdin goes non-TTY
mid-flow); the check must run regardless of err so the caller's
non-interactive fallback triggers instead of reporting 'N failed'.

IMPORTANT: --plugin non-TTY path no longer blocks on fmt.Fscanln(os.Stdin)
(which hangs on an open, dataless pipe). The valuer now has three explicit
modes: reader (in!=nil, tests/pipe), interactive prompt.Input (TTY), and
non-interactive value sources (--from-env/--secret) for non-TTY — a secret
with no source is skipped, never read from stdin. promptOne is reduced to a
reader-only helper (no os.Stdin/Fscanln/term), removing the hang at its
source; the unused golang.org/x/term import is dropped. --plugin gains
--from-env and --secret for CI parity with the main path.

IMPORTANT: register --all (Bool) on 'secrets setup'; mutually exclusive with
--only; explicit form of the existing default (set every declared secret).

IMPORTANT: add TestSecretsSetupNonTTYDoesNotHang — builds the real wfctl
binary and runs 'secrets setup --config <tmp>' with empty piped (non-TTY)
stdin under a 20s exec deadline; asserts non-zero exit, output names the
missing secret, and it returns well before the deadline. Regression guard
for the two findings above (follows TestLinkedVersionOverridesBuildInfo).

MINORS: (a) go mod tidy moves charm.land/bubbles/v2 to the direct require
block (it is directly imported). (b) non-interactive valuer's actionable
'no value for secret ...' error is now printed alongside each [failed] line
instead of being swallowed by the engine accumulator. (c) remove write-only
selected/done bool fields from the prompt models. (d) replace bespoke
stableSort with sort.Strings in secrets_audit.go.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:303: parsing iteration count: invalid syntax
baseline-bench.txt:320359: parsing iteration count: invalid syntax
baseline-bench.txt:593132: parsing iteration count: invalid syntax
baseline-bench.txt:916056: parsing iteration count: invalid syntax
baseline-bench.txt:1245700: parsing iteration count: invalid syntax
baseline-bench.txt:1792355: parsing iteration count: invalid syntax
benchmark-results.txt:305: parsing iteration count: invalid syntax
benchmark-results.txt:302967: parsing iteration count: invalid syntax
benchmark-results.txt:636556: parsing iteration count: invalid syntax
benchmark-results.txt:919229: parsing iteration count: invalid syntax
benchmark-results.txt:1233207: parsing iteration count: invalid syntax
benchmark-results.txt:1542415: 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               9.898m ± 64%
ComponentLoad-4                     3.579m ±  8%
ComponentExecute-4                  1.942µ ±  2%
PoolContention/workers-1-4          1.088µ ±  3%
PoolContention/workers-2-4          1.087µ ±  2%
PoolContention/workers-4-4          1.090µ ±  1%
PoolContention/workers-8-4          1.087µ ±  1%
PoolContention/workers-16-4         1.114µ ±  2%
ComponentLifecycle-4                3.614m ±  1%
SourceValidation-4                  2.324µ ±  1%
RegistryConcurrent-4                809.4n ±  3%
LoaderLoadFromString-4              3.633m ±  2%
geomean                             19.29µ

                            │ 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                  9.565m ± 69%
ComponentLoad-4                        3.494m ±  0%
ComponentExecute-4                     1.852µ ±  3%
PoolContention/workers-1-4             1.019µ ±  3%
PoolContention/workers-2-4             1.015µ ±  3%
PoolContention/workers-4-4             1.030µ ±  2%
PoolContention/workers-8-4             1.024µ ±  1%
PoolContention/workers-16-4            1.032µ ±  2%
ComponentLifecycle-4                   3.566m ±  1%
SourceValidation-4                     2.102µ ±  0%
RegistryConcurrent-4                   780.4n ±  5%
LoaderLoadFromString-4                 3.586m ±  1%
geomean                                18.35µ

                            │ 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                  287.7n ± 5%
CircuitBreakerExecution_Success-4          21.52n ± 2%
CircuitBreakerExecution_Failure-4          66.16n ± 0%
geomean                                    74.26n

                                  │ 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                     297.9n ± 6%
CircuitBreakerExecution_Success-4             22.66n ± 0%
CircuitBreakerExecution_Failure-4             70.92n ± 1%
geomean                                       78.22n

                                  │ 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       │
IaCStateBackend_InProcess-4              326.1n ± 23%
IaCStateBackend_GRPC-4                   9.503m ±  3%
JQTransform_Simple-4                     698.1n ± 30%
JQTransform_ObjectConstruction-4         1.492µ ±  1%
JQTransform_ArraySelect-4                3.372µ ±  1%
JQTransform_Complex-4                    38.56µ ±  1%
JQTransform_Throughput-4                 1.820µ ±  1%
SSEPublishDelivery-4                     64.84n ±  0%
geomean                                  3.862µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
IaCStateBackend_InProcess-4              416.0 ± 0%
IaCStateBackend_GRPC-4                 5.808Mi ± 9%
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.31Ki ± 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      │
IaCStateBackend_InProcess-4              2.000 ± 0%
IaCStateBackend_GRPC-4                  6.839k ± 0%
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    328.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         │
IaCStateBackend_InProcess-4                 322.6n ± 17%
IaCStateBackend_GRPC-4                      10.17m ±  1%
JQTransform_Simple-4                        659.2n ± 25%
JQTransform_ObjectConstruction-4            1.415µ ±  1%
JQTransform_ArraySelect-4                   3.401µ ±  1%
JQTransform_Complex-4                       41.76µ ±  0%
JQTransform_Throughput-4                    1.733µ ±  1%
SSEPublishDelivery-4                        64.67n ±  2%
geomean                                     3.854µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
IaCStateBackend_InProcess-4                 416.0 ± 0%
IaCStateBackend_GRPC-4                    5.853Mi ± 6%
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.31Ki ± 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       │
IaCStateBackend_InProcess-4                 2.000 ± 0%
IaCStateBackend_GRPC-4                     6.857k ± 0%
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       328.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.092µ ± 1%
SchemaValidation_AllFields-4                 1.657µ ± 5%
SchemaValidation_FormatValidation-4          1.581µ ± 2%
SchemaValidation_ManySchemas-4               1.844µ ± 5%
geomean                                      1.516µ

                                    │ 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                       1.080µ ± 1%
SchemaValidation_AllFields-4                    1.628µ ± 3%
SchemaValidation_FormatValidation-4             1.552µ ± 1%
SchemaValidation_ManySchemas-4                  1.596µ ± 4%
geomean                                         1.444µ

                                    │ 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.201µ ± 14%
EventStoreAppend_SQLite-4                  1.263m ±  3%
GetTimeline_InMemory/events-10-4           14.18µ ±  2%
GetTimeline_InMemory/events-50-4           80.14µ ±  2%
GetTimeline_InMemory/events-100-4          160.7µ ±  3%
GetTimeline_InMemory/events-500-4          800.8µ ± 16%
GetTimeline_InMemory/events-1000-4         1.297m ±  1%
GetTimeline_SQLite/events-10-4             105.1µ ±  1%
GetTimeline_SQLite/events-50-4             248.2µ ±  1%
GetTimeline_SQLite/events-100-4            422.1µ ±  0%
GetTimeline_SQLite/events-500-4            1.808m ±  0%
GetTimeline_SQLite/events-1000-4           3.518m ±  1%
geomean                                    228.4µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  806.0 ± 5%
EventStoreAppend_SQLite-4                  1.983Ki ± 3%
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.45Ki

                                   │ 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                   1.076µ ± 11%
EventStoreAppend_SQLite-4                     1.060m ±  3%
GetTimeline_InMemory/events-10-4              13.20µ ±  6%
GetTimeline_InMemory/events-50-4              72.21µ ±  2%
GetTimeline_InMemory/events-100-4             146.4µ ± 24%
GetTimeline_InMemory/events-500-4             566.0µ ±  1%
GetTimeline_InMemory/events-1000-4            1.158m ±  2%
GetTimeline_SQLite/events-10-4                85.57µ ±  1%
GetTimeline_SQLite/events-50-4                221.6µ ±  0%
GetTimeline_SQLite/events-100-4               390.8µ ±  1%
GetTimeline_SQLite/events-500-4               1.674m ±  0%
GetTimeline_SQLite/events-1000-4              3.273m ±  1%
geomean                                       200.6µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                     759.5 ± 6%
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.13Ki

                                   │ benchmark-results.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

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

if err != nil {
return fmt.Errorf("audit: open %s: %w", path, err)
}
defer f.Close() //nolint:errcheck
@intel352 intel352 merged commit 969547a into main May 30, 2026
28 checks passed
@intel352 intel352 deleted the feat/wfctl-secrets-wizard branch May 30, 2026 21:14
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