Skip to content

Commit

Permalink
v0.0.30: improved windows and headless linux support
Browse files Browse the repository at this point in the history
  • Loading branch information
benburkert committed May 2, 2024
1 parent 2fe6f49 commit bce0148
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 88 deletions.
32 changes: 17 additions & 15 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

var (
ErrSignedOut = errors.New("sign in required")
ErrGnomeKeyringRequired = errors.New("gnome-keyring is required for secure credential storage.\n ! Please install with your host package manager")
ErrGnomeKeyringRequired = fmt.Errorf("gnome-keyring required for secure credential storage: %w", ErrSignedOut)
)

// NB: can't call this Client since the name is already taken by an openapi
Expand Down Expand Up @@ -64,23 +64,15 @@ func NewClient(cfg *cli.Config) (*Session, error) {

if apiToken, err = kr.Get(keyring.APIToken); err == keyring.ErrNotFound {
return anc, ErrSignedOut
} else if err != nil {
if runtime.GOOS == "linux" {
_, err := exec.LookPath("gnome-keyring-daemon")
if err != nil {
_, err := exec.LookPath("apt-get")
if err == nil {
return nil, fmt.Errorf("%w:\n sudo apt-get install gnome-keyring", ErrGnomeKeyringRequired)
}
_, err = exec.LookPath("yum")
if err == nil {
return nil, fmt.Errorf("%w:\n sudo yum install gnome-keyring", ErrGnomeKeyringRequired)
}
return nil, fmt.Errorf("%w.", ErrGnomeKeyringRequired)
}
}
if err != nil {
if gnomeKeyringMissing() {
return anc, ErrGnomeKeyringRequired
}

return nil, fmt.Errorf("reading PAT token from keyring failed: %w", err)
}

if !strings.HasPrefix(apiToken, "ap0_") || len(apiToken) != 64 {
return nil, fmt.Errorf("read invalid PAT token from keyring")
}
Expand Down Expand Up @@ -390,3 +382,13 @@ const NotFoundErr = StatusCodeError(http.StatusNotFound)

func (err StatusCodeError) StatusCode() int { return int(err) }
func (err StatusCodeError) Error() string { return fmt.Sprintf("unexpected %d status response", err) }

func gnomeKeyringMissing() bool {
if runtime.GOOS != "linux" {
return false
}
if path, _ := exec.LookPath("gnome-keyring-daemon"); path != "" {
return false
}
return true
}
20 changes: 20 additions & 0 deletions auth/models/signin.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,23 @@ func (m *SignInChecker) View() string {
}
return b.String()
}

type KeyringUnavailable struct {
ShowGnomeKeyringHint bool
}

func (m *KeyringUnavailable) Init() tea.Cmd { return nil }

func (m *KeyringUnavailable) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil }

func (m *KeyringUnavailable) View() string {
var b strings.Builder
fmt.Fprintln(&b, ui.Warning("Unable to access keyring, credentials will not be stored."))

if m.ShowGnomeKeyringHint {
fmt.Fprintln(&b, ui.StepHint("gnome-keyring is required for secure credential storage."))
fmt.Fprintln(&b, ui.StepHint("Please install with your host package manager"))
}

return b.String()
}
40 changes: 12 additions & 28 deletions auth/signin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package auth

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"

"github.com/atotto/clipboard"
Expand All @@ -17,6 +14,7 @@ import (
"github.com/anchordotdev/cli/api"
"github.com/anchordotdev/cli/auth/models"
"github.com/anchordotdev/cli/keyring"
cliModels "github.com/anchordotdev/cli/models"
"github.com/anchordotdev/cli/ui"
)

Expand Down Expand Up @@ -49,7 +47,7 @@ func (s *SignIn) RunTUI(ctx context.Context, drv *ui.Driver) error {
drv.Activate(ctx, s.Hint)

anc, err := api.NewClient(cfg)
if err != nil && err != api.ErrSignedOut {
if err != nil && !errors.Is(err, api.ErrSignedOut) {
return err
}

Expand Down Expand Up @@ -78,7 +76,7 @@ func (s *SignIn) RunTUI(ctx context.Context, drv *ui.Driver) error {
}

if err := browser.OpenURL(codes.VerificationUri); err != nil {
return err
drv.Activate(ctx, &cliModels.Browserless{Url: codes.VerificationUri})
}

drv.Activate(ctx, new(models.SignInChecker))
Expand All @@ -95,38 +93,24 @@ func (s *SignIn) RunTUI(ctx context.Context, drv *ui.Driver) error {
}
cfg.API.Token = patToken

userInfo, err := fetchUserInfo(cfg)
anc, err = api.NewClient(cfg)
if err != nil {
return err
}

userInfo, err := anc.UserInfo(ctx)
if err != nil {
return err
}

kr := keyring.Keyring{Config: cfg}
if err := kr.Set(keyring.APIToken, cfg.API.Token); err != nil {
return err
drv.Activate(ctx, &models.KeyringUnavailable{
ShowGnomeKeyringHint: errors.Is(err, api.ErrGnomeKeyringRequired),
})
}

drv.Send(models.UserSignInMsg(userInfo.Whoami))

return nil
}

func fetchUserInfo(cfg *cli.Config) (*api.Root, error) {
anc, err := api.NewClient(cfg)
if err != nil {
return nil, err
}

res, err := anc.Get("")
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected response code: %d", res.StatusCode)
}

var userInfo *api.Root
if err := json.NewDecoder(res.Body).Decode(&userInfo); err != nil {
return nil, err
}
return userInfo, nil
}
6 changes: 3 additions & 3 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ func init() {
joinedGoPaths := strings.Join(goPaths, ",<gopath>,") + ",<gopath>"
replacements := strings.Split(joinedGoPaths, ",")
replacements = append(replacements, runtime.GOROOT(), "<goroot>")

if pwd, _ := os.Getwd(); pwd != "" {
replacements = append(replacements, pwd, "<pwd>")
}

stackPathReplacer = strings.NewReplacer(replacements...)
}

Expand Down Expand Up @@ -212,7 +212,7 @@ func ReportError(ctx context.Context, drv *ui.Driver, cmd *cobra.Command, args [
if stack != "" {
fmt.Fprintf(&body, "**Stack:**\n```\n%s\n```\n", normalizeStack(stack))
}
fmt.Fprintf(&body, "**Stdout:**\n```\n%s\n```\n", strings.TrimRight(string(drv.FinalOut()), "\n"))
fmt.Fprintf(&body, "**Stdout:**\n```\n%s\n```\n", strings.TrimRight(string(drv.LastView), "\n"))
q.Add("body", body.String())

reportErrorConfirmCh := make(chan struct{})
Expand Down
118 changes: 83 additions & 35 deletions cmd/anchor/.goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ builds:
- CGO_ENABLED=0
id: linux
goos: [linux]
goarch: ['amd64','arm64','386']
goarch: ["amd64", "arm64", "386"]
- <<: *build_defaults
id: macos
goos: [darwin]
goarch: ['amd64','arm64']
goarch: ["amd64", "arm64"]
- <<: *build_defaults
id: windows
goos: [windows]
goarch: ['amd64','386']
goarch: ["amd64", "386"]

archives:
- id: linux
Expand Down Expand Up @@ -64,39 +64,87 @@ brews:
assert_match "anchor is a command line interface for the Anchor certificate management platform.", shell_output("#{bin}/anchor")
msi:
- name: "msi-builder-{{ .MsiArch }}"
id: anchor-msi
ids:
- windows
wxs: ./windows/app.wxs
extra_files:
- ./windows/als2.ico
- ../../LICENSE
mod_timestamp: "{{ .CommitTimestamp }}"
- name: "msi-builder-{{ .MsiArch }}"
id: anchor-msi
ids:
- windows
wxs: ./windows/app.wxs
extra_files:
- ./windows/als2.ico
- ../../LICENSE
mod_timestamp: "{{ .CommitTimestamp }}"

chocolateys:
- name: anchor
ids:
- anchor-msi
package_source_url: https://github.com/anchordotdev/cli
owners: Anchor Security, Inc.
title: Anchor CLI
authors: Anchor
project_url: https://anchor.dev
use: msi
url_template: "https://github.com/anchordotdev/cli/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
copyright: 2024 Anchor Security, Inc.
license_url: https://raw.githubusercontent.com/anchordotdev/cli/main/LICENSE
require_license_acceptance: false
project_source_url: https://github.com/anchordotdev/cli
docs_url: https://anchor.dev/docs
bug_tracker_url: https://github.com/anchordotdev/cli/issues
icon_url: https://anchor.dev/images/als2.png
tags: "security tls ssl certificates localhost https cryptography encryption acme cli x509 X.509"
summary: "Command-line tools for Anchor.dev"
description: |
- name: anchor
ids:
- anchor-msi
package_source_url: https://github.com/anchordotdev/cli
owners: Anchor Security, Inc.
title: Anchor CLI
authors: Anchor
project_url: https://anchor.dev
use: msi
url_template: "https://github.com/anchordotdev/cli/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
copyright: 2024 Anchor Security, Inc.
license_url: https://raw.githubusercontent.com/anchordotdev/cli/main/LICENSE
require_license_acceptance: false
project_source_url: https://github.com/anchordotdev/cli
docs_url: https://anchor.dev/docs
bug_tracker_url: https://github.com/anchordotdev/cli/issues
icon_url: https://anchor.dev/images/als2.png
tags: "security tls ssl certificates localhost https cryptography encryption acme cli x509 X.509"
summary: "Command-line tools for Anchor.dev"
description: |
anchor is a command line interface for the Anchor certificate management platform.
It provides a developer friendly interface for certificate management.
release_notes: "https://github.com/anchordotdev/cli/releases/tag/v{{ .Version }}"
api_key: "{{ .Env.CHOCOLATEY_API_KEY }}"
source_repo: "https://push.chocolatey.org/"
release_notes: "https://github.com/anchordotdev/cli/releases/tag/v{{ .Version }}"
api_key: "{{ .Env.CHOCOLATEY_API_KEY }}"
source_repo: "https://push.chocolatey.org/"

winget:
- name: cli
publisher: Anchor
short_description: "Command-line tools for Anchor.dev"
license: mit
publisher_url: https://anchor.dev
publisher_support_url: https://github.com/anchordotdev/cli/issues
package_identifier: Anchor.cli
ids:
- anchor-msi
use: msi
product_code: C5F94F62-E3CC-48E2-AB3C-4DED8C6099E9
url_template: "https://github.com/anchordotdev/cli/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
homepage: https://anchor.dev
description: |
anchor is a command line interface for the Anchor certificate management platform.
It provides a developer friendly interface for certificate management.
license_url: https://raw.githubusercontent.com/anchordotdev/cli/main/LICENSE
copyright: 2024 Anchor Security, Inc.
release_notes: "{{.Changelog}}"
release_notes_url: "https://github.com/anchordotdev/cli/releases/tag/v{{ .Version }}"
tags:
[
"security",
"tls",
"ssl",
"certificates",
"localhost",
"https",
"cryptography",
"encryption",
"acme",
"cli",
"x509",
"X.509",
]
repository:
owner: anchordotdev
name: winget-pkgs
branch: "{{.ProjectName}}-{{.Version}}"
pull_request:
enabled: true
check_boxes: true
base:
owner: microsoft
name: winget-pkgs
branch: master
6 changes: 3 additions & 3 deletions ui/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Driver struct {
Out io.Reader
out io.ReadWriter
test bool
lastView string
LastView string
}

func NewDriverTest(ctx context.Context) *Driver {
Expand Down Expand Up @@ -172,12 +172,12 @@ func (d *Driver) View() string {
out += mdl.View()
}
normalizedOut := spinnerReplacer.Replace(out)
if out != "" && normalizedOut != d.lastView {
if out != "" && normalizedOut != d.LastView {
separator := fmt.Sprintf("─── %s ", reflect.TypeOf(d.active).Elem().Name())
separator = separator + strings.Repeat("─", 80-utf8.RuneCountInString(separator))
fmt.Fprintln(d.out, separator)
fmt.Fprint(d.out, normalizedOut)
d.lastView = normalizedOut
d.LastView = normalizedOut
}
return out
}
Expand Down
21 changes: 17 additions & 4 deletions ui/styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var (
Skip = header.Copy().Faint(true).SetString("# Skipped:").Render
Hint = hint.Copy().Render
Underline = lipgloss.NewStyle().Underline(true).Render
Warning = header.Copy().SetString(bgBanana(fgMidnight("!")) + fgBanana(" Warning:")).Render

// https://github.com/charmbracelet/lipgloss/blob/v0.9.1/style.go#L149

Expand All @@ -28,19 +29,31 @@ var (
StepInProgress = lipgloss.NewStyle().SetString(" *").Render
StepPrompt = lipgloss.NewStyle().SetString(" " + Prompt.Render("?")).Render

Announce = lipgloss.NewStyle().Background(colorBrandSecondary).Render
bgBanana = lipgloss.NewStyle().Background(colorBanana).Render

Accentuate = lipgloss.NewStyle().Italic(true).Render
Action = lipgloss.NewStyle().Bold(true).Foreground(colorBrandPrimary).Render
Announce = lipgloss.NewStyle().Background(colorBrandSecondary).Render
Error = lipgloss.NewStyle().Bold(true).Foreground(colorDanger).Render
Emphasize = lipgloss.NewStyle().Bold(true).Render
EmphasizeUnderline = lipgloss.NewStyle().Bold(true).Underline(true).Render
Titlize = lipgloss.NewStyle().Bold(true).Render
URL = lipgloss.NewStyle().Faint(true).Underline(true).Render
Whisper = lipgloss.NewStyle().Faint(true).Render

colorBrandPrimary = lipgloss.Color("#ff6000")
colorBrandSecondary = lipgloss.Color("#7000ff")
colorDanger = lipgloss.Color("#E63757")
fgBanana = lipgloss.NewStyle().Foreground(colorBanana).Render
fgMidnight = lipgloss.NewStyle().Foreground(colorMidnight).Render

colorBrandPrimary = colorMandarin
colorBrandSecondary = colorGrape
colorDanger = colorApple

// Brand Palette
colorMidnight = lipgloss.Color("#110C18")
colorGrape = lipgloss.Color("#60539E")
colorMandarin = lipgloss.Color("#FF6000")
colorApple = lipgloss.Color("#CE4433")
colorBanana = lipgloss.Color("#FBF5AC")

Prompt = lipgloss.NewStyle().Foreground(colorBrandPrimary)

Expand Down

0 comments on commit bce0148

Please sign in to comment.