Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
"artipacked",
"binname",
"binpath",
"bsdtar",
"cimd",
"clidocs",
"containedctx",
"coverprofile",
"cpuprof",
"credstore",
Expand All @@ -28,7 +30,10 @@
"memprof",
"mgechev",
"mktemp",
"mtimes",
"nolint",
"pipefail",
"rundll",
"techdocs",
"trimpath",
"urfave",
Expand Down
22 changes: 22 additions & 0 deletions .jscpd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"threshold": 0,
"reporters": ["console"],
"ignore": [
"**/.git/**",
"**/megalinter-reports/**",
"**/*cache*/**",
"**/*.json",
"**/*.yaml",
"**/*.yml",
"**/*.md",
"**/*.html",
"**/*.xml",
"**/*.jpg",
"**/*.png",
"**/*.svg",
"**/*.zip",
"**/*.bin",
"**/bin/**",
"**/*_test.go"
]
}
87 changes: 63 additions & 24 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,11 @@ lfx-cli/

### Current State

This repo is under active scaffolding. Auth and API commands are currently
stubs; real implementations land in follow-on work:

- `lfx auth login` / `status` / `logout`
- `lfx auth token`
- `lfx api`

Credential storage (system keychain via `99designs/keyring`) and the Auth0
CIMD client are tracked separately.
`lfx auth login` / `status` / `token` / `logout` are fully implemented,
including the Auth0 Device Code flow, refresh-token exchange, and
credential storage (system keychain via `99designs/keyring`, with a plain
`--insecure-storage` fallback). `lfx api` remains a stub; its
implementation lands in follow-on work.

**No container build**: this project produces binary artifacts only,
distributed via GitHub Releases, the `install.sh` curl-style installer
Expand Down Expand Up @@ -150,16 +146,17 @@ func NewExampleCommand() *cli.Command {

### Package Comments

Every file in a package must start with the same `// Package <name> ...`
doc comment immediately above the `package` declaration. Revive's
`package-comments` rule itself only requires one such comment per package,
but MegaLinter's `GO_REVIVE` linter defaults to `GO_REVIVE_CLI_LINT_MODE:
list_of_files`, invoking revive with a flat list of files instead of
`./...`. Under that mode revive loses per-package grouping and flags any
file lacking the comment, so duplicating the identical comment across
every file in a package is a required workaround for how MegaLinter calls
revive here, not an inherent revive requirement. Do not vary the wording
between files in the same package.
Every non-test (`*.go`, not `*_test.go`) file in a package must start with
the same `// Package <name> ...` doc comment immediately above the
`package` declaration. Revive's `package-comments` rule itself only
requires one such comment per package, but MegaLinter's `GO_REVIVE` linter
defaults to `GO_REVIVE_CLI_LINT_MODE: list_of_files`, invoking revive with
a flat list of files instead of `./...`. Under that mode revive loses
per-package grouping and flags any non-test file lacking the comment, so
duplicating the identical comment across every non-test file in a package
is a required workaround for how MegaLinter calls revive here, not an
inherent revive requirement. Do not vary the wording between files in the
same package.

## Documentation Generation

Expand Down Expand Up @@ -230,9 +227,51 @@ release binaries may be missing even though the GitHub Release exists.

1. **Add Commands**: Create new commands in `internal/commands/` following
the established pattern
2. **Package Comments**: Every new `*.go` file must include the same
`// Package <name> ...` doc comment as the rest of its package
2. **Package Comments**: Every new non-test `*.go` file must include the
same `// Package <name> ...` doc comment as the rest of its package
(see "Package Comments" above; `*_test.go` files are exempt)
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
keep dependencies current. This upgrades module dependencies only, not the
Go toolchain itself (`go.mod`'s `go` directive) -- see the toolchain policy
below before touching that.
4. **Go toolchain version**: Freely bump `go.mod`'s `go` directive to the
latest available *patch* release (e.g. `1.X.Y` → `1.X.{Y+1}`) to pick up
security fixes. Do **not** bump the *minor* version (e.g. `1.X.x` →
`1.{X+1}.x`) unless the user explicitly asks for it, **and** you've
validated it against the Go version MegaLinter itself bundles --
MegaLinter runs several linters (e.g. `golangci-lint`) against its own
bundled Go version, and a `go.mod` directive newer than that bundled
version breaks those checks.

To find MegaLinter's bundled Go version:

```bash
# 1. Find the MegaLinter flavor and pinned version tag used in CI.
grep -A1 'oxsecurity/megalinter' .github/workflows/*.yml
# e.g. "uses: oxsecurity/megalinter/flavors/<flavor>@<sha> # <tag>"

# 2. Fetch that flavor's Dockerfile and read its GO_ALPINE_VERSION (or
# GO_IMAGE_VERSION) build arg.
curl -s "https://raw.githubusercontent.com/oxsecurity/megalinter/<tag>/flavors/<flavor>/Dockerfile" \
| grep -i 'GO_ALPINE_VERSION\|GO_IMAGE_VERSION'
```

`go.mod`'s `go` directive must never exceed that bundled version. Staying
one minor version behind it (rather than matching its minor *and* patch
exactly) leaves room to always take the latest patch release for security
fixes without ever being blocked by MegaLinter's own bundled patch version
lagging behind a newly disclosed vulnerability.

There's no built-in `go` subcommand to look up the latest patch release
for a given minor version -- query the official `go.dev/dl` JSON feed
instead:

```bash
# Find the latest patch release for the minor version pinned in go.mod.
MINOR=$(grep '^go ' go.mod | awk '{print $2}' | cut -d. -f1,2)
curl -s "https://go.dev/dl/?mode=json&include=all" \
| jq -r --arg m "go${MINOR}." '.[].version | select(startswith($m))' \
| sort -V | tail -1
```
5. **Code Quality**: Run `make check` before commits
6. **Documentation**: Update README.md for user-facing changes
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,27 @@ 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.
Credential Manager, Linux Secret Service/KWallet/`pass`). Which of these is
actually used can vary between invocations on the same machine (e.g. Secret
Service reachable in one shell session but not another); pass
`--backend` to pin it to one explicitly (see `lfx auth backends`
for the available names). Once a login has pinned a backend, later commands
must pass the same `--backend` value. 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
lfx auth login --backend=keychain
```

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

> **Note:** This project is under active development. Authentication and API
> commands are currently stubs; see the
> **Note:** This project is under active development. `lfx auth` is fully
> implemented; `lfx api` is currently a stub. See the
> [LFXV2-2509 epic](https://linuxfoundation.atlassian.net/browse/LFXV2-2509)
> for status.

Expand Down
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
// SPDX-License-Identifier: MIT
module github.com/linuxfoundation/lfx-cli

go 1.26.5
go 1.25.14

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
github.com/urfave/cli/v3 v3.11.0
golang.org/x/oauth2 v0.36.0
)

require (
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/dvsekhvalnov/jose2go v1.10.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
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMF
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/dvsekhvalnov/jose2go v1.10.0 h1:5RmEnUoQBMBURnk346hX3dKqG60Jkf9qkp6dkLsFx60=
github.com/dvsekhvalnov/jose2go v1.10.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=
Expand All @@ -31,8 +31,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
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=
github.com/urfave/cli/v3 v3.11.0 h1:P/euJp99kb9p0tlVY+iYTLYYTAQlfl0hR2gUO1Img1Q=
github.com/urfave/cli/v3 v3.11.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
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=
Expand Down
Loading
Loading