Skip to content

Scaffold Go CLI application with stubbed auth command#1

Merged
emsearcy merged 8 commits into
mainfrom
lfxv2-2511-scaffold-cli
Jul 15, 2026
Merged

Scaffold Go CLI application with stubbed auth command#1
emsearcy merged 8 commits into
mainfrom
lfxv2-2511-scaffold-cli

Conversation

@emsearcy

@emsearcy emsearcy commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Scaffolds the initial Go CLI application structure per LFXV2-2511.

  • Initializes the Go module (github.com/linuxfoundation/lfx-cli)
  • Adopts urfave/cli/v3 for subcommand routing
  • Adds urfave/cli-docs/v3 for Markdown doc generation via a hidden lfx docs command
  • Stubs out lfx auth login/token/status/logout and lfx api (no-op, to be implemented in follow-on tickets)
  • Adds a Makefile mirroring lfx-mcp's build/check conventions
  • Configures GoReleaser for linux/darwin/windows amd64+arm64 builds (windows/arm64 excluded), with a tag-push release workflow
  • Adds MegaLinter workflow/config, .cspell.json, .lycheeignore, .yamllint, and .gitignore
  • Pins the license-header-check reusable workflow to a commit SHA (no tags published upstream) and disables Go module caching in the release workflow, addressing zizmor's unpinned-uses and cache-poisoning audits
  • Adds AGENTS.md with build, test, and contribution guidance
  • Updates the README with install instructions and usage

Acceptance criteria (all verified locally)

  • go build ./cmd/lfx produces a working binary
  • lfx --help shows available commands
  • lfx auth login prints a stub message
  • lfx docs emits structured Markdown for all commands
  • GoReleaser config validates (goreleaser check) and publishes via tag-push workflow

Jira

LFXV2-2511

🤖 Generated with GitHub Copilot (via OpenCode)

- Initialize Go module (github.com/linuxfoundation/lfx-cli)
- Adopt urfave/cli/v3 for subcommand routing
- Add urfave/cli-docs/v3 for Markdown doc generation via hidden 'lfx docs'
- Stub out auth login/token/status/logout and api subcommands
- Add Makefile mirroring lfx-mcp build/check conventions
- Configure GoReleaser for linux/darwin/windows amd64+arm64 builds
  (windows/arm64 excluded)
- Add release-tag workflow to publish binaries via GoReleaser on tag push,
  with per-job permissions and all actions pinned to commit SHA
- Add MegaLinter workflow/config, .cspell.json, .lycheeignore, .yamllint,
  and .gitignore
- Pin the license-header-check reusable workflow to a commit SHA (no tags
  published upstream) and disable Go module caching in the release
  workflow to address zizmor's unpinned-uses and cache-poisoning audits
- Add AGENTS.md with build, test, and contribution guidance
- Update README with install instructions and usage

Assisted-by: github-copilot:claude-sonnet-5
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 17:47
@emsearcy emsearcy requested a review from a team as a code owner July 14, 2026 17:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Scaffolds the initial Go-based LFX CLI, including stub commands, documentation generation, release automation, and development tooling.

Changes:

  • Adds the CLI entry point and stubbed auth/API commands.
  • Adds build, lint, documentation, and contributor tooling.
  • Configures multi-platform releases and GitHub workflows.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Adds installation and usage guidance.
Makefile Adds development and build targets.
internal/commands/docs.go Adds Markdown documentation generation.
internal/commands/auth.go Adds stubbed authentication commands.
internal/commands/api.go Adds the stubbed API command.
go.sum Records dependency checksums.
go.mod Defines the module and dependencies.
cmd/lfx/main.go Adds the CLI entry point.
AGENTS.md Documents development workflows.
.yamllint Configures YAML linting.
.mega-linter.yml Configures MegaLinter.
.lycheeignore Adds link-check exclusions.
.goreleaser.yaml Configures release artifacts.
.gitignore Adds generated-file exclusions.
.github/workflows/release-tag.yml Publishes tagged releases.
.github/workflows/mega-linter.yml Runs MegaLinter on pull requests.
.github/workflows/license-header-check.yml Pins the reusable license workflow.
.cspell.json Configures spell checking.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/lfx/main.go Outdated
Comment thread internal/commands/auth.go Outdated
Comment thread internal/commands/api.go Outdated
Comment thread internal/commands/docs.go Outdated
Go source files used 'Copyright The Linux Foundation and contributors.'
but the reusable license-header-check workflow is configured with the
longer 'Copyright The Linux Foundation and each contributor to LFX.'
string, causing CI to flag all four new Go files as missing their
license header.

Assisted-by: github-copilot:claude-sonnet-5
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 17:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 18 changed files in this pull request and generated 4 comments.

Comment thread .mega-linter.yml Outdated
Comment thread Makefile Outdated
Comment thread Makefile Outdated
Comment thread .github/workflows/release-tag.yml Outdated
- Remove stray ENABLE_LINTERS allow-list from .mega-linter.yml that was
  silently restricting MegaLinter to only run zizmor
- Flatten the Makefile build target so it always rebuilds instead of
  relying on a stale file-timestamp prerequisite that misses git
  revision, deleted files, and go.mod changes
- Point install-tools at the golangci-lint/v2 module path instead of
  the obsolete v1 module
- Constrain the GoReleaser action version to '~> v2' instead of
  'latest', so a future v3 release can't silently break old tags

Assisted-by: github-copilot:claude-sonnet-5
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 18:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 18 changed files in this pull request and generated 4 comments.

Comment thread cmd/lfx/main.go
Comment thread Makefile Outdated
Comment thread Makefile Outdated
Comment thread README.md
- Fall back to the module version from debug.ReadBuildInfo() when no
  -ldflags version is injected (e.g. 'make build' or
  'go install ...@latest'), instead of always reporting 'dev'
- Drop the Makefile's separate 'git describe' VERSION/-X main.version
  injection now that main.go derives the same information from Go's
  automatic VCS build-info stamping; GoReleaser still injects the
  precise tagged version via -ldflags
- Serialize 'all' (clean/check/build) and 'check' (fmt before the
  read-only checks) via recursive $(MAKE) calls so 'make -j' can't
  race on bin/lfx or on source files being formatted while read

Assisted-by: github-copilot:claude-sonnet-5
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 20:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 16 out of 18 changed files in this pull request and generated 4 comments.

Comment thread AGENTS.md
Comment thread Makefile Outdated
Comment thread AGENTS.md
Comment thread .github/workflows/mega-linter.yml
Address review comments from copilot-pull-request-reviewer:

- .github/workflows/build.yaml: added a standalone Build workflow that
  runs go build, gofmt -l, go vet, and go test on every PR, since
  MegaLinter's revive-only run (GO_GOLANGCI_LINT disabled) never
  compiles the Go packages, so CI could otherwise pass non-building
  code (per copilot-pull-request-reviewer)
- AGENTS.md: clarified the Package Comments section to explain that
  MegaLinter's GO_REVIVE_CLI_LINT_MODE defaults to list_of_files
  (verified locally with revive 1.15.0), under which revive loses
  per-package grouping and requires the doc comment on every file,
  rather than overstating Revive's own package-comments rule (per
  copilot-pull-request-reviewer)
- Makefile: reworded the build-flags comment to accurately describe
  that a local build's pseudo-version already encodes VCS revision and
  dirty state (verified via go version -m), while go install of a
  tagged version reports the resolved tag in a different format (per
  copilot-pull-request-reviewer)

No change made to the release-tag.yml/AGENTS.md release procedure
(flagged as a possible workflow trigger issue): `gh release create`
run by a human triggers the tag-push workflow normally; the GITHUB_TOKEN
recursion guard only suppresses workflow-triggered-workflow chains, not
human-driven API calls. This matches the identical, working pattern in
lfx-mcp.

Resolves 4 review threads.

Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 20:37
- .cspell.json: added "gofmt" to the word list, introduced by the new
  build.yaml workflow
- .mega-linter.yml: added REPOSITORY_KICS to DISABLE_ERRORS_LINTERS.
  It's currently disabled upstream by MegaLinter itself (supply chain
  compromise), so marking it non-blocking here prevents a future
  upstream restore from unexpectedly breaking the build before we've
  reviewed it

Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
@emsearcy

Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed (round 2)

Commits: 5eb7ca2, fce9541

Changes Made

  • Makefile: reworded the build-flags comment. Verified with go version -m that a local go build already embeds a pseudo-version (v0.0.0-<time>-<revision>[+dirty]) encoding VCS revision and dirty state; the comment previously implied this info was missing (per copilot-pull-request-reviewer)
  • AGENTS.md: clarified the Package Comments section. Reproduced locally with revive 1.15.0 that MegaLinter's GO_REVIVE_CLI_LINT_MODE defaults to list_of_files, which causes revive to lose per-package grouping and flag files individually — confirmed revive ./... passes but revive file1.go file2.go fails on an uncommented file in the same package. Reworded to explain this is a MegaLinter workaround, not revive's own rule (per copilot-pull-request-reviewer)
  • .github/workflows/build.yaml (new): standalone workflow running go build, a gofmt -l format check, go vet, and go test on every PR, since MegaLinter's revive-only run (GO_GOLANGCI_LINT disabled) never compiles the Go packages (per copilot-pull-request-reviewer)
  • .cspell.json: added "gofmt" to the word list (introduced by the new workflow)
  • .mega-linter.yml: added REPOSITORY_KICS to DISABLE_ERRORS_LINTERS — it's currently disabled upstream by MegaLinter itself, so this keeps it non-blocking if a future upstream restore re-enables it

No Change Needed

  • AGENTS.md release procedure: verified gh release create, run interactively by a human (not from inside a workflow using GITHUB_TOKEN), does trigger the push: tags: event normally — the recursion guard only suppresses workflow-triggered-workflow chains, not human-driven API calls. lfx-mcp uses this identical release procedure with an identical trigger, confirming it works in practice (flagged by copilot-pull-request-reviewer)

Threads Resolved

4 of 4 unresolved threads addressed in this iteration.

- .cspell.json: added "kics" to the word list, flagged by the newly
  added REPOSITORY_KICS comment in .mega-linter.yml
- .mega-linter.yml: added SPELL_CSPELL to DISABLE_ERRORS_LINTERS.
  There's no easy local feedback loop for spelling issues before
  pushing, so keep them non-blocking to avoid unnecessary PR cycles
  for words that just need adding to the dictionary.

Signed-off-by: Eric Searcy <eric@linuxfoundation.org>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated 1 comment.

Comment thread Makefile
Comment on lines +11 to +17
# Build flags. Version is not injected via -ldflags: `go build` already
# embeds a pseudo-version (encoding the VCS revision, commit time, and
# dirty state) into the binary's module version, which main.go reads via
# debug.ReadBuildInfo() as a fallback. A local `make build` therefore
# reports a traceable pseudo-version like v0.0.0-<time>-<revision>[+dirty],
# while `go install ...@vX.Y.Z` reports the resolved tag instead; the
# formats differ, but both identify the exact source that was built.

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.

This is based on pre-Go 1.24 semantics, which no longer apply here. Prior to Go 1.24, debug.ReadBuildInfo().Main.Version was always (devel) for a local build of the main module, full stop. Go 1.24 changed this (see https://tip.golang.org/doc/go1.24): go build now sets the main module's version to a VCS-derived pseudo-version (with a +dirty suffix if applicable) instead of (devel), whenever local VCS info is available and -buildvcs isn't disabled.

This repo's go.mod requires go 1.26.5, well past that change. Reproduced on current HEAD with no -buildvcs override anywhere in the repo (GOFLAGS empty, default -buildvcs=auto):

$ go build -ldflags="-s -w" -o /tmp/lfx_verify ./cmd/lfx
$ /tmp/lfx_verify --version
lfx version v0.0.0-20260714204748-822de299abeb
$ go version -m /tmp/lfx_verify | grep -i vcs
	build	vcs=git
	build	vcs.revision=822de299abeb6c140efa6b07b0e73ee5c0e57141
	build	vcs.time=2026-07-14T20:47:48Z
	build	vcs.modified=false

Main.Version is the pseudo-version, not (devel), and correctly reflects the actual commit. main.go's != "(devel)" check only falls back to the literal dev string when there's genuinely no VCS info available (e.g. building from a tarball with no .git), not for a normal git checkout. No change needed.

Copilot AI review requested due to automatic review settings July 14, 2026 20:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated no new comments.

- Makefile: added revive to the install-tools target (it was missing,
  even though `make revive` already existed and expected it on PATH)
- Makefile: install-tools now warns if $(go env GOPATH)/bin isn't on
  PATH, since installed tools (golangci-lint, goreleaser, revive)
  won't be found otherwise

Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 14, 2026 21:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated no new comments.

@dealako dealako left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey @emsearcy — nice work on this scaffold. This is the 9th automated review pass on the PR (8 rounds from Copilot plus this one), and it shows: the codebase is in excellent shape. I ran an independent review myself plus dispatched a security-auditor and a code-reviewer-pro subagent in parallel to cross-check.

Overview: Clean Go module scaffold using urfave/cli/v3, stub auth/api commands with clear ticket references for follow-on work, a hidden docs command for Markdown generation, and solid CI/release tooling (pinned Actions, scoped permissions, GoReleaser v2 pinned, a dedicated build.yaml that actually compiles/vets/tests the code since MegaLinter's Revive-only pass doesn't). Version resolution in main.go (ldflags → debug.ReadBuildInfo()"dev") is correct and well-commented.

Reconciliation with prior Copilot rounds: I checked all 8 prior Copilot review threads — license header wording, golangci-lint v2 module path, GoReleaser version pinning, Makefile phony/ordering (parallel-make races), MegaLinter's stray ENABLE_LINTERS allow-list, the missing go build/test coverage gap (now closed by build.yaml), Revive package-comments guidance, and ReadBuildInfo Go 1.24+ semantics — all were fixed with clear, verifiable commits, and the two most recent Copilot passes (after fce9541/822de29/a4df953) found zero new issues. Nothing outstanding from those rounds.

My review + subagent findings:

  • 🔴 Blocking: 0
  • 🟡 Minor: 0
  • ⚪ Nit: 1 — Makefile:108-110 (install-tools) installs golangci-lint/goreleaser/revive via @latest. Flagged by my security subagent for supply-chain consistency with the rest of the repo's SHA-pinning discipline. After self-challenge: this target isn't invoked by any CI workflow (MegaLinter uses its own pinned Docker image; build.yaml doesn't call it), so it has no bearing on release reproducibility or CI security — it only affects a contributor's local toolchain. Worth a follow-up if you want fully deterministic local tooling, but not blocking.
  • ❔ Question: 0

No security findings of consequence, no test-coverage gap worth flagging (stub commands with no branching logic; acceptance criteria explicitly call for manual verification here), no correctness issues, no merge conflicts.

Final decision:Approved with minor comments (the one nit above, non-blocking)

Comment thread Makefile
@echo "Installing development tools..."
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
go install github.com/goreleaser/goreleaser/v2@latest
go install github.com/mgechev/revive@latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[nit] Unpinned dev-tool installs

Issue: golangci-lint, goreleaser, and revive are installed via @latest here.
Proof: this target isn't invoked by CI (MegaLinter uses its own pinned Docker image at v9.6.0; build.yaml doesn't call make install-tools), so this only affects a contributor's local toolchain — no release reproducibility or CI security impact.
Why it matters: minor inconsistency with the rest of the repo's SHA/version-pinning discipline; a contributor's local linter version could drift from what they expect.
Fix: optional — pin to specific released versions (e.g. @v2.x.y) if fully deterministic local tooling matters to you. Not blocking.

@emsearcy emsearcy merged commit 3efc0b7 into main Jul 15, 2026
8 checks passed
@emsearcy emsearcy deleted the lfxv2-2511-scaffold-cli branch July 15, 2026 00:34
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.

3 participants