wfctl audit: 13 CLI fixes, registry data, plugin ecosystem#324
Merged
wfctl audit: 13 CLI fixes, registry data, plugin ecosystem#324
Conversation
Wave 2 design: Okta (~130 steps), Datadog (~120), LaunchDarkly (~100), Permit.io (~80), Salesforce (~75), OpenLMS (~120) — all MIT, community tier. Release plan: tag untagged plugins, create validation scenarios 51-59 with mock HTTP backends in workflow-scenarios. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase A: 13 CLI fixes (help exit codes, plugin-dir rename, flag ordering, etc.) Phase B: 2 registry data fix tasks Phase C: 5 plugin ecosystem tasks (GitHub URL install, lockfile, goreleaser) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alignment check identified missing coverage for design requirement B5. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Permit.io fits alongside Casbin in the existing authz plugin rather than a standalone repo. Same multi-provider pattern as payments (Stripe + PayPal). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the flag from -data-dir to -plugin-dir across runPluginInstall, runPluginList, runPluginUpdate, runPluginRemove, and runPluginInfo for consistency with other wfctl commands. Keep -data-dir as a working deprecated alias. Update pluginUsage() to document -plugin-dir. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add checkTrailingFlags() to detect when flags are passed after positional arguments, and wire it into runPluginInit, runRegistryAdd, and runRegistryRemove. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add isHelpRequested() helper that detects flag.ErrHelp propagated through the pipeline engine. In main(): - No-args case now exits 0 (showing help is not an error) - Help requests in dispatch exit 0 without printing engine error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add normalizePluginName() stripping "workflow-plugin-" prefix so users can reference plugins by short name (e.g. "authz") or full name (e.g. "workflow-plugin-authz") interchangeably. Wire into FetchManifest and SearchPlugins. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add isWorkflowYAML() that checks the first 100 lines of a file for top-level modules:, workflows:, or pipelines: keys. Files found by --dir that don't match are skipped with a stderr message, preventing false validation failures on GitHub Actions CI files and other YAML. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before downloading, compare installed plugin.json version against the registry manifest version. If equal, print "already at latest version" and skip. If different, print "Updating from X to Y..." and proceed. Also adds -config flag to plugin update for registry config override. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Improve the error message from the generic "no config file found" to a helpful message that explains what the config needs and how to generate one. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verify that install uses -plugin-dir (custom dir) instead of the default data/plugins path. This guards the fix from Task 2 that updated runPluginUpdate to pass --plugin-dir, not --data-dir, when calling runPluginInstall. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace `COPY go.mod go.sum ./` with `COPY go.mod ./` + `COPY go.sum* ./` so the generated Dockerfile works whether or not go.sum exists yet. The glob pattern in the second COPY is a no-op when go.sum is absent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Read raw YAML to extract the imports: list before calling config.LoadFromFile. After loading, print "Resolved N import(s): ..." to stderr so users can see which files were included. This makes the validate command transparent about include/import resolution. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allow users to pass the config file as a positional argument instead of always requiring -config, e.g. `wfctl deploy cloud myapp.yaml`. Applied to: runDeployDocker, runK8sGenerate, runK8sApply, runDeployCloud. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… format Add custom UnmarshalJSON on PluginManifest that detects whether the capabilities field is an array (new CapabilityDecl format) or an object (legacy registry format with moduleTypes/stepTypes/triggerTypes). When the legacy object format is detected, its type lists are merged into the top-level ModuleTypes, StepTypes, and TriggerTypes fields so callers always find types in a consistent location regardless of plugin.json format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolve pluginDir to absolute path before displaying the binary path, so users see /absolute/path/to/plugin instead of relative data/plugins/foo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add MinEngineVersion field to PluginManifest and checkEngineCompatibility() to plugin/loader.go. The loader calls this on every plugin load — if the running engine version is older than the plugin's declared minimum, a WARNING is printed to stderr. No hard fail to allow testing newer plugins against older engines. SetEngineVersion() on PluginLoader threads the engine version through. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add parseGitHubRef() to detect owner/repo[@Version] references. Add installFromGitHub() to query GitHub Releases API and download assets matching {repo}_{os}_{arch}.tar.gz. In runPluginInstall, when the registry lookup fails and the input looks like a GitHub ref, fall back to direct GitHub installation. This allows: wfctl plugin install GoCodeAlone/workflow-plugin-authz@v0.3.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add PluginLockfile/PluginLockEntry types with load/save that preserve all other .wfctl.yaml fields (project, git, deploy) on round-trip. Wire into plugin install: - `wfctl plugin install` (no args): reads .wfctl.yaml plugins section and installs all pinned entries - `wfctl plugin install <name>@<version>`: after successful install, updates/creates the plugins entry in .wfctl.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reference .goreleaser.yml for plugin repos documenting required conventions:
- binary using {{ .ProjectName }} template
- archives include plugin.json
- before/after hooks to template plugin.json version from release tag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs in Task 16 GitHub install fallback: 1. Pass pluginName (version-stripped) to FetchManifest, not nameArg which may carry @Version suffix and cause lookup failures. 2. Compute destDir after normalizing the repo short name so owner/repo installs go to data/plugins/<shortname> not the raw input. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task 17: installFromLockfile now passes just the plugin name (no @Version) to runPluginInstall so updateLockfile doesn't fire and overwrite the pinned entry in .wfctl.yaml during a lockfile-driven restore. Task 18: checkEngineCompatibility uses slog.Warn instead of fmt.Fprintf to stderr, consistent with the rest of the codebase. Remove unused "os" import from loader.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace local file path reference with ^0.2.0 from GitHub Packages registry. Fixes CI failures where the local tarball doesn't exist. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
⏱ Benchmark Results✅ No significant performance regressions detected. benchstat comparison (baseline → PR)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--helpexit codes,-data-dir→-plugin-dirrename, trailing flag detection, full plugin name resolution (workflow-plugin-authz→authz), plugin-dir honored, update version check, deploy positional config args, init Dockerfile go.sum handling, validate --dir skips non-workflow YAML, validate reports imports, infra error messages, plugin info absolute paths, PluginManifest legacy capabilities UnmarshalJSONinternal→builtin), ratchet downloads, authz name verification, schema validation gap, version sync scriptowner/repo@version),.wfctl.yamllockfile support, engineminEngineVersionwarning, goreleaser standardization across 12 plugin repos, registry auto-sync CI on releaseDesign
See: docs/plans/2026-03-12-wfctl-audit-design.md
Implementation Plan
See: docs/plans/2026-03-12-wfctl-audit.md
Changes
cmd/wfctl/workflow-registry/Addresses: PRs #321, #322, Issue #316
🤖 Generated with Claude Code