Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,33 @@
"words": [
"aquasecurity",
"artipacked",
"binname",
"binpath",
"cimd",
"clidocs",
"coverprofile",
"cpuprof",
"credstore",
"ehthumbs",
"esac",
"fprintln",
"goarch",
"gobin",
"gofmt",
"golangci",
"goreleaser",
"goos",
"gopath",
"kics",
"ldflags",
"lfx",
"lfxv",
"linuxfoundation",
"memprof",
"mgechev",
"mktemp",
"pipefail",
"techdocs",
"trimpath",
"urfave",
"zizmor"
],
Expand Down
91 changes: 80 additions & 11 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ name: Publish Tagged Release
permissions: {}

jobs:
goreleaser:
name: GoReleaser
runs-on: ubuntu-latest
release:
name: Build and upload release artifacts
runs-on: macos-latest
# Runs on macos-latest (rather than ubuntu-latest) so darwin binaries
# can be built natively with CGO_ENABLED=1: keyring's KeychainBackend
# is compiled only under the "darwin && cgo" build tag, which a
# cross-compiled, CGO_ENABLED=0 darwin build can't satisfy. linux and
# windows binaries are still pure cross-compiles (CGO_ENABLED=0, no
# cgo-only backends there), which works the same from any host OS.

permissions:
contents: write
Expand All @@ -34,19 +40,82 @@ jobs:
# into a release build (zizmor cache-poisoning audit).
cache: false

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
# Constrained to v2 (the action's documented default) so a
# future GoReleaser v3 release doesn't silently break old tags.
version: "~> v2"
args: release --clean
- name: Build and archive release binaries
run: |
set -euo pipefail

name="lfx-cli"
version="${GITHUB_REF_NAME#v}"
# Reproducible builds: pin every archived file's mtime to the
# commit timestamp (rather than build/checkout time), and strip
# build-path information from the binary. actions/checkout sets
# file mtimes to checkout time, not the original commit time (git
# doesn't track per-file mtimes at all), so LICENSE/README need
# pinning here too, not just the binary.
# https://reproducible-builds.org/docs/archives/
commit_epoch="$(git log -1 --format=%ct)"
mtime="$(date -u -r "${commit_epoch}" +%Y%m%d%H%M.%S)"
touch -t "${mtime}" LICENSE LICENSE-docs README.md

# goos, goarch, cgo_enabled
targets=(
"linux amd64 0"
"linux arm64 0"
"windows amd64 0"
"darwin amd64 1"
"darwin arm64 1"
)

for target in "${targets[@]}"; do
read -r goos goarch cgo_enabled <<< "${target}"

workdir="$(mktemp -d)"
binname="lfx"
[ "${goos}" = "windows" ] && binname="lfx.exe"
binpath="${workdir}/${binname}"

GOOS="${goos}" GOARCH="${goarch}" CGO_ENABLED="${cgo_enabled}" go build \
-trimpath \
-ldflags="-s -w -X main.version=${version}" \
-o "${binpath}" ./cmd/lfx
touch -t "${mtime}" "${binpath}"

if [ "${goos}" = "windows" ]; then
archive="${name}_${goos}_${goarch}.zip"
zip -X -j "${archive}" "${binpath}" LICENSE LICENSE-docs README.md
else
archive="${name}_${goos}_${goarch}.tar.gz"
# Pipe through gzip -n rather than tar's built-in -z: bsdtar's
# gzip writer embeds the current wall-clock time in the gzip
# header regardless of the archived files' mtimes, which
# would otherwise make the archive bytes differ on every run
# despite the pinned mtimes above.
tar -cf - -C "${workdir}" "${binname}" -C "${GITHUB_WORKSPACE}" LICENSE LICENSE-docs README.md \
| gzip -n > "${archive}"
fi

shasum -a 256 "${archive}" >> checksums.txt
rm -rf "${workdir}"
done

- name: Upload release artifacts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail

gh release upload "${GITHUB_REF_NAME}" \
lfx-cli_linux_amd64.tar.gz \
lfx-cli_linux_arm64.tar.gz \
lfx-cli_windows_amd64.zip \
lfx-cli_darwin_amd64.tar.gz \
lfx-cli_darwin_arm64.tar.gz \
checksums.txt \
--repo "${GITHUB_REPOSITORY}" --clobber

publish-docs:
name: Publish CLI docs to gh-pages
needs: goreleaser
needs: release
runs-on: ubuntu-latest

permissions:
Expand Down
52 changes: 0 additions & 52 deletions .goreleaser.yaml

This file was deleted.

23 changes: 16 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ CLI (`lfx auth login` → `lfx auth token`).
subcommand routing
- **Docs generation**: [`urfave/cli-docs/v3`](https://github.com/urfave/cli-docs)
for LLM/agent-friendly Markdown reference docs (`lfx docs`)
- **Release automation**: [GoReleaser](https://goreleaser.com/) for
multi-arch binary builds published to GitHub Releases
- **Release automation**: a single `release-tag.yml` GitHub Actions job
(running on `macos-latest`) cross-compiles linux/windows binaries and
natively builds cgo-enabled darwin binaries, then uploads all archives
to the GitHub Release
- **Output**: user-facing command output uses plain `fmt.Println`/
`fmt.Fprintln`, not `log/slog`. This is intentional: unlike the
JSON-structured `slog` logging convention used by LFX's long-running
services, `lfx` is an interactive CLI with no log aggregator consuming
its output.

## Architecture Overview

Expand All @@ -29,7 +36,8 @@ lfx-cli/
│ └── lfx/ # Main application entry point
├── internal/
│ └── commands/ # CLI subcommand implementations
├── .goreleaser.yaml # Multi-arch release build configuration
├── .github/workflows/
│ └── release-tag.yml # Multi-arch release build/upload
├── go.mod # Go module definition
├── Makefile # Build automation
├── README.md # User documentation
Expand Down Expand Up @@ -85,7 +93,6 @@ make fmt # Format code
make vet # Run go vet
make lint # Run golangci-lint (if installed)
make revive # Run revive (if installed)
make goreleaser-check # Validate .goreleaser.yaml (if goreleaser installed)
make check # Run all of the above
```

Expand Down Expand Up @@ -202,7 +209,7 @@ explicitly instructed.
Do **not** create or push git tags manually. Instead, use the GitHub
Releases UI (or `gh` CLI) to create a release; GitHub will create the tag
automatically, and the **Publish Tagged Release** GitHub Actions workflow
will run GoReleaser to build and publish multi-arch binaries.
will build and upload multi-arch binaries to it.

```bash
# Determine the next version by inspecting the latest tag.
Expand All @@ -225,5 +232,7 @@ release binaries may be missing even though the GitHub Release exists.
the established pattern
2. **Package Comments**: Every new `*.go` file must include the same
`// Package <name> ...` doc comment as the rest of its package
3. **Code Quality**: Run `make check` before commits
4. **Documentation**: Update README.md for user-facing changes
3. **Dependencies**: Run `go get -u ./... && go mod tidy` before every PR to
keep dependencies current
4. **Code Quality**: Run `make check` before commits
5. **Documentation**: Update README.md for user-facing changes
17 changes: 3 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright The Linux Foundation and each contributor to LFX.
# SPDX-License-Identifier: MIT

.PHONY: all build clean check fmt vet lint revive goreleaser-check test test-coverage run deps install-tools megalinter help
.PHONY: all build clean check fmt vet lint revive test test-coverage run deps install-tools megalinter help

# Build variables
BINARY_NAME=lfx
Expand Down Expand Up @@ -41,7 +41,7 @@ clean:
# the read-only checks run; those are safe to parallelize with each other.
check:
$(MAKE) fmt
$(MAKE) vet lint revive goreleaser-check
$(MAKE) vet lint revive

# Format Go code
fmt:
Expand Down Expand Up @@ -71,15 +71,6 @@ revive:
echo "revive not installed, skipping..."; \
fi

# Validate the GoReleaser config (if available)
goreleaser-check:
@echo "Validating .goreleaser.yaml..."
@if command -v goreleaser >/dev/null 2>&1; then \
goreleaser check; \
else \
echo "goreleaser not installed, skipping..."; \
fi

# Run tests
test:
@echo "Running tests..."
Expand All @@ -106,12 +97,11 @@ deps:
install-tools:
@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
@gobin="$$(go env GOPATH)/bin"; \
case ":$$PATH:" in \
*":$$gobin:"*) ;; \
*) echo "Warning: $$gobin is not in your PATH; installed tools (golangci-lint, goreleaser, revive) won't be found. Add it to your PATH, e.g.: export PATH=\"$$PATH:$$gobin\"" ;; \
*) echo "Warning: $$gobin is not in your PATH; installed tools (golangci-lint, revive) won't be found. Add it to your PATH, e.g.: export PATH=\"$$PATH:$$gobin\"" ;; \
esac

# Run MegaLinter locally via Docker (matches CI Go flavor at v9.6.0).
Expand All @@ -131,7 +121,6 @@ help:
@echo " vet - Run go vet"
@echo " lint - Run golangci-lint"
@echo " revive - Run revive"
@echo " goreleaser-check - Validate .goreleaser.yaml"
@echo " test - Run tests"
@echo " test-coverage - Run tests with coverage report"
@echo " run - Build and run the CLI (pass args via ARGS=...)"
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ lfx auth logout
lfx api <method> <path>
```

Credentials (refresh token, cached access token) are stored in your
operating system's credential store by default (macOS Keychain, Windows
Credential Manager, Linux Secret Service/KWallet/`pass`). Pass
`--insecure-storage` to any `auth` subcommand to instead store credentials
in a plain, unencrypted, owner-only file, at the cost of weaker protection
for the stored tokens. On Windows, this owner-only mode relies on inherited
directory permissions rather than a real ACL, since Go's `Chmod(0600)` maps
to the read-only attribute there rather than restricting access to the
current user.

```bash
lfx auth login --insecure-storage
```

Run `lfx --help` or `lfx <command> --help` for full details on any command.

> **Note:** This project is under active development. Authentication and API
Expand Down
11 changes: 10 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ module github.com/linuxfoundation/lfx-cli
go 1.26.5

require (
github.com/99designs/keyring v1.2.2
github.com/urfave/cli-docs/v3 v3.1.0
github.com/urfave/cli/v3 v3.10.1
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/danieljoos/wincred v1.2.3 // indirect
github.com/dvsekhvalnov/jose2go v1.8.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/term v0.45.0 // indirect
)
31 changes: 29 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dvsekhvalnov/jose2go v1.8.0 h1:LqkkVKAlHFfH9LOEl5fe4p/zL02OhWE7pCufMBG2jLA=
github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/urfave/cli-docs/v3 v3.1.0 h1:Sa5xm19IpE5gpm6tZzXdfjdFxn67PnEsE4dpXF7vsKw=
github.com/urfave/cli-docs/v3 v3.1.0/go.mod h1:59d+5Hz1h6GSGJ10cvcEkbIe3j233t4XDqI72UIx7to=
github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY=
github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading
Loading