Skip to content

feat(cli): scaffold the cli/ Go module for the signet binary - #335

Merged
blockchain-maxis merged 3 commits into
blockchain-maxis:mainfrom
ibochivincent-lang:feat/scaffold-cli-module
Sep 2, 2026
Merged

feat(cli): scaffold the cli/ Go module for the signet binary#335
blockchain-maxis merged 3 commits into
blockchain-maxis:mainfrom
ibochivincent-lang:feat/scaffold-cli-module

Conversation

@ibochivincent-lang

Copy link
Copy Markdown
Contributor

closes #251

Summary

There was no CLI in the repo. Every other CLI issue (config file, machine-readable output, wallet linking, key management) is blocked on this module existing. Adds cli/ as a standalone Go module, living beside the pnpm workspace rather than inside it, mirroring the split between orchestration/UX (Go) and anything that must execute Soroban semantics (Rust, packages/contracts).

Changes

  • cli/go.mod: new Go module github.com/blockchain-maxis/signet/cli, go 1.25.0, depending only on github.com/spf13/cobra (+ its own transitive deps). No cgo anywhere.
  • cli/cmd/signet/main.go: the binary's entrypoint. version/commit package vars, overridable via -ldflags "-X main.version=... -X main.commit=...", default to dev/none.
  • cli/internal/cmd/root.go: the Cobra root command (signet), with --version wired to print signet version <version> (commit <commit>).
    • Worth calling out: Cobra only renders the Usage: section of --help when a command is Runnable() or has subcommands — neither was true for a bare scaffold with no subcommands attached yet, so signet --help was printing only the Long description with no usage. Fixed by giving root a RunE that falls through to cmd.Help(), which also makes a bare signet invocation show help instead of doing nothing.
  • cli/internal/{link,keys,spec}/doc.go: placeholder packages (per the issue's proposed layout) for wallet-linking, key management, and the deployment API's typed request/response models — each just a package doc comment, implemented in follow-up issues.
  • cli/.golangci.yml: golangci-lint v2 config (standard linters + bodyclose, errcheck, ineffassign, staticcheck, unused; gofmt/goimports formatters).
  • cli/internal/cmd/root_test.go: tests for --version output, --help usage output, and the bare-invocation-shows-help behavior — the last one is a regression test for the Usage-section bug above.
  • .github/workflows/ci.yml: new cli job — go build ./..., go vet ./..., go test ./..., golangci-lint run — matching the existing per-area job pattern (contracts, web, etc.).
  • README.md: added cli to the directory-structure and scripts tables.

Verification

  • go build ./..., go vet ./..., go test ./... — all pass (3/3 tests).
  • golangci-lint run ./... — 0 issues.
  • Built the binary with real ldflags and exercised it manually:
    • signet --help and bare signet both print the description and a Usage: section with the -h/-v flags.
    • signet --versionsignet version v0.1.0 (commit abcdef1).
  • Cross-compiled with CGO_ENABLED=0 for linux/amd64 and darwin/arm64 — both succeed, confirming no cgo dependency crept in.
  • pnpm workspace (typecheck/lint/test) and node scripts/check-docs.mjs are unaffected — cli/ isn't part of the pnpm workspace glob.

Every CLI issue is blocked on this module existing. Add cli/ as a
standalone Go module (go 1.25, no cgo) alongside the pnpm workspace,
building a signet binary via cobra: cmd/signet/main.go is the
entrypoint, internal/cmd holds the command tree, and internal/link,
internal/keys, internal/spec are placeholder packages for the
wallet-linking, key-management, and API-spec work that follows.

signet --version carries a version and commit string injected via
ldflags. signet --help and a bare `signet` invocation both print real
usage text — cobra only renders the Usage: section when a command is
Runnable() or has subcommands, so the root command needed an explicit
RunE (falling through to cmd.Help()) to show it before any subcommand
exists. golangci-lint is configured via cli/.golangci.yml, and a new
CI job builds, vets, tests, and lints the module.

Verified go build/go vet/go test all pass, and the binary
cross-compiles with CGO_ENABLED=0 for linux/amd64 and darwin/arm64.
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@ibochivincent-lang Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

@ibochivincent-lang is attempting to deploy a commit to the blockchainmaxis-8449's projects Team on Vercel.

A member of the Team first needs to authorize it.

@netlify

netlify Bot commented Aug 30, 2026

Copy link
Copy Markdown

Deploy Preview for stellar-signet ready!

Name Link
🔨 Latest commit d886eef
🔍 Latest deploy log https://app.netlify.com/projects/stellar-signet/deploys/6a97ff6db63b91000770ca1c
😎 Deploy Preview https://deploy-preview-335--stellar-signet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

README conflict: main deleted packages/ui, so its row goes and the new cli row
stays.

Also fixes the Go lint step, which had never run — this is the first PR to add
a Go job, and fork CI stayed action_required. cli/.golangci.yml is a v2 config
(`version: "2"`, and the v2-only `formatters:` block) but the workflow pinned
golangci-lint-action@v6, which drives golangci-lint v1 and passes v1-only flags.
Moved to action v8 with a pinned v2.1.6 rather than `version: latest`, so the
linter cannot change underneath the repo between runs.

Verified locally with go1.25.12: go build, go vet, go test all pass, gofmt -l
is empty, golangci-lint v2.1.6 reports 0 issues, and CGO_ENABLED=0 cross-builds
succeed for darwin/arm64, darwin/amd64, linux/amd64 and windows/amd64.
The v2.1.6 binary is built with go1.24 and refuses a module targeting
go 1.25.0:

  can't load config: the Go language version (go1.24) used to build
  golangci-lint is lower than the targeted Go version (1.25.0)

My earlier local check compiled it from source with go1.25.12, which is why it
passed there and failed on CI. v2.13.2 ships built with go1.27; verified with
the actual release binary against cli/: 0 issues.
@blockchain-maxis
blockchain-maxis merged commit a4f7a53 into blockchain-maxis:main Sep 2, 2026
10 of 11 checks passed
blockchain-maxis added a commit to ibochivincent-lang/signet that referenced this pull request Sep 2, 2026
blockchain-maxis#335 landed as a squash, so its files came back as add/add conflicts against
this branch's copy of the same commit. Verified main's cli/ tree is identical
to 8dbbe29 (the commit this branch was built on) before resolving, so:

- cli/README.md, cli/internal/cmd/root.go, cli/internal/cmd/root_test.go: take
  this branch's versions, which are blockchain-maxis#335's content plus this PR's config work.
- .github/workflows/ci.yml, README.md: take main's, which carry the golangci
  fixes made while merging blockchain-maxis#335 (action v8 + a golangci-lint built with Go
  1.25) and main's removal of the packages/ui row.

Verified after resolving: go build, go vet, go test, gofmt -l and
golangci-lint v2.13.2 all clean; node scripts/check-docs.mjs passes.
blockchain-maxis added a commit to Lazyartist1/signet that referenced this pull request Sep 2, 2026
packages/ui was removed from the workspace, so its CODEOWNERS entry pointed at
a path that no longer exists. The Go CLI module landed in blockchain-maxis#335 and had no rule.
blockchain-maxis added a commit that referenced this pull request Sep 2, 2026
) (#339)

* chore(infra): add CODEOWNERS file for area-based review assignment (#231)

* chore(infra): drop the deleted packages/ui rule, add cli/

packages/ui was removed from the workspace, so its CODEOWNERS entry pointed at
a path that no longer exists. The Go CLI module landed in #335 and had no rule.

---------

Co-authored-by: blockchain-maxis <267648998+blockchain-maxis@users.noreply.github.com>
blockchain-maxis added a commit to ibochielizabeth-spec/signet that referenced this pull request Sep 2, 2026
blockchain-maxis#335 and blockchain-maxis#336 landed as squashes, so their files came back as add/add
conflicts against this branch's cherry-picks of the same work:
- .github/workflows/ci.yml, README.md: take main's (carries the golangci
  action/version fixes and the packages/ui removal).
- cli/internal/cmd/root.go: main's version is blockchain-maxis#336's fuller one (config
  resolution in PersistentPreRunE); this branch only adds AddCommand(newLinkCmd()).
- cli/README.md: take this branch's, which documents the link command.

Also made the non-JSON output stop claiming a link that did not happen.
internal/keys and internal/spec are still scaffolds, so 'Linked aquawolf to
G… (testnet)' reported a success for a no-op. It now reads 'Validated … Not
yet submitted — the on-chain claim is not implemented.' The --json contract is
untouched, which is what issue blockchain-maxis#264 and the downstream stack depend on.

Verified: go build/vet/test, gofmt -l, golangci-lint v2.13.2 (0 issues), plus
a manual run of all three paths — --json emits exactly one JSON line on
stdout, the human path writes the honest summary, and an invalid handle leaves
stdout empty with the error on stderr and exit 1.
blockchain-maxis added a commit to Mamavee001/signet that referenced this pull request Sep 2, 2026
…error

Conflict resolution against the squashed blockchain-maxis#335/blockchain-maxis#336/blockchain-maxis#342:
- .github/workflows/ci.yml, README.md: main's.
- cli/cmd/signet/main.go: this branch's exit-code mapping (the point of the PR).
- cli/internal/cmd/link.go, cli/README.md: main's honest 'Validated … not yet
  submitted' wording rather than this branch's older 'Linked …'.
- cli/internal/link/link.go: this branch's ValidationError and public-key
  redaction.

The secret-hygiene test only inspected cobra's output buffers. The command tree
runs with SilenceErrors, so a returned error never reaches those buffers —
cmd/signet/main.go prints it to the process's real stderr. The test therefore
could not fail no matter what an error message said, which is the half of the
acceptance criterion ('stdout, stderr, or an error string') that most needed
covering. Now asserts the error string too.

That immediately caught a real leak. The public-key path was already careful
not to echo its input, but the handle path was not:

  $ signet link SASAAEJC6P5U…UUEMCD --public-key GASAAEJC…
  invalid handle "SASAAEJC6P5U…UUEMCD": expected 1-32 lowercase letters…

Reproduced with the built binary, not just in a test — a seed put in the wrong
argument slot was read straight back into shell history and any CI log. Errors
now pass the value through redactSecrets, so an ordinary typo is still echoed
('invalid handle "Bad Handle"') while a secret-shaped value becomes
'[redacted: secret-shaped value]'.

Verified: go build, go vet, gofmt -l, golangci-lint v2.13.2 (0 issues) and
go test -race ./... all clean, plus the built binary — redaction confirmed,
typo feedback intact, and exit codes 2 for invalid input / 0 for success.
blockchain-maxis added a commit to Mamavee001/signet that referenced this pull request Sep 2, 2026
Conflict resolution against the squashed blockchain-maxis#335/blockchain-maxis#336/blockchain-maxis#342:
- .github/workflows/ci.yml, README.md: main's.
- cli/cmd/signet/main.go, cli/internal/link/link.go, cli/internal/cmd/link.go:
  this branch's, which carry blockchain-maxis#345's exit-code mapping that this PR is stacked
  on. Taking main's first silently dropped it — caught because the shim then
  forwarded exit 1 instead of 2 in the end-to-end check below.
- cli/README.md: this branch's, with the stale 'Linked …' example updated to
  main's honest 'Validated … not yet submitted' wording.
- scripts/check-docs.mjs: keep the CLI_RELEASE_ENABLED / NPM_TOKEN allowlist
  entries (GitHub repo variable and Actions secret, not app env).

Reapplied the handle-error secret redaction from blockchain-maxis#345, which this branch
predates.

Verified the release path end to end rather than by reading it — built a
linux/amd64 binary with the workflow's own ldflags, staged it through
scripts/release/stage-platform-package.mjs, pinned with pin-shim-version.mjs,
laid the two packages out as npm would under node_modules/@signet, and ran the
shim:

  --version              -> signet version 9.9.9-test (commit deadbeef)
  link --json            -> one JSON object, nothing else
  invalid handle, $? -> 2   (the shim forwards the binary's real exit code)

Then reverted the staged binary and the 9.9.9-test version pins.

Publishing stays inert on merge: release-cli.yml triggers only on a cli-v*
tag (none exist) and the npm publish step is additionally gated on
vars.CLI_RELEASE_ENABLED, which is not set.

go build/vet/test -race, gofmt, golangci-lint v2.13.2 (0 issues) and
check-docs all clean.
blockchain-maxis added a commit to Otfrugger/signet that referenced this pull request Sep 2, 2026
This PR's only real change is the cross-compile smoke build; everything else in
the diff is cherry-picked blockchain-maxis#335/blockchain-maxis#336/blockchain-maxis#342/blockchain-maxis#345, all now squashed onto main. Took
main's version of every one of those files.

ci.yml keeps all three improvements rather than either side:
- `go test -race ./...` from this branch (issue blockchain-maxis#252 asks for -race; main
  still had a plain `go test`),
- the golangci-lint action v8 + pinned v2.13.2 from main,
- the four-target cross-compile smoke build this PR adds. Noted in the comment
  that the target set matches what release-cli.yml publishes, so the two
  cannot silently diverge.

Verified locally: all four targets build with CGO_ENABLED=0, and
go test -race ./... is clean across all 7 packages.
blockchain-maxis added a commit to Otfrugger/signet that referenced this pull request Sep 2, 2026
Everything except cli/internal/browser/ and its docs was a cherry-pick of
blockchain-maxis#335/blockchain-maxis#336/blockchain-maxis#342/blockchain-maxis#345/blockchain-maxis#356/blockchain-maxis#357/blockchain-maxis#358, all now on main — took main's for all of
those. scripts/check-docs.mjs keeps all three allowlist entries rather than
either side's pair (WAYLAND_DISPLAY from this branch, CLI_RELEASE_ENABLED and
NPM_TOKEN from blockchain-maxis#346).

Verified the fallback behaves as issue blockchain-maxis#257 requires, by driving OpenOrPrint
with DISPLAY and WAYLAND_DISPLAY unset:

  headless, browser allowed -> prints 'Open this URL to continue: <url>', returns nil
  --no-browser              -> same

so the opener's failure is absorbed rather than propagated, and both paths
reach the developer at the same URL.

Left unwired deliberately, unlike blockchain-maxis#357's CheckStellarCLI: there is no call site
to attach it to yet — `signet link` performs no approval flow (that lands with
the loopback server and the pairing endpoints), so wiring it now would mean
inventing the flow rather than connecting to one. Both the package doc and
cli/README say so plainly.

go build/vet, gofmt, golangci-lint v2.13.2 (0 issues), go test -race ./... and
check-docs all clean.
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.

Scaffold the cli/ Go module — the @signet/cli binary

2 participants