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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="docs/commands/optiqor-hori.jpg" alt="Optiqor" width="520">

Check warning on line 2 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (Optiqor)

Check warning on line 2 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (hori)

Check warning on line 2 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (optiqor)
</p>

<p align="center"><b>Detect. Fix. Prove.</b></p>
Expand All @@ -9,11 +9,11 @@
[![npm](https://img.shields.io/npm/v/@optiqor/cli.svg?label=%40optiqor%2Fcli&color=blue)](https://www.npmjs.com/package/@optiqor/cli)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/optiqor/optiqor-cli.svg)](https://pkg.go.dev/github.com/optiqor/optiqor-cli)
[![CI](https://img.shields.io/github/actions/workflow/status/optiqor/optiqor/ci.yml?branch=main&label=ci)](https://github.com/optiqor/optiqor-cli/actions/workflows/ci.yml)
[![CI](https://img.shields.io/github/actions/workflow/status/optiqor/optiqor-cli/ci.yml?branch=main&label=ci)](https://github.com/optiqor/optiqor-cli/actions/workflows/ci.yml)
[![Downloads](https://img.shields.io/npm/dm/@optiqor/cli.svg)](https://www.npmjs.com/package/@optiqor/cli)

```sh
npx @optiqor/cli analyze ./my-helm-chart

Check warning on line 16 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (optiqor)
```

That is it. One command. No setup. No account. Cost findings for your Kubernetes workloads in under three seconds.
Expand All @@ -22,7 +22,7 @@

## Table of Contents

- [Why Optiqor CLI](#why-optiqor-cli)

Check warning on line 25 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (Optiqor)
- [Install](#install)
- [Quick Start](#quick-start)
- [How It Works](#how-it-works)
Expand All @@ -32,20 +32,20 @@
- [CLI vs Agent vs Sandbox](#cli-vs-agent-vs-sandbox)
- [Configuration](#configuration)
- [Privacy and Accuracy](#privacy-and-accuracy)
- [The Full Optiqor Platform](#the-full-optiqor-platform)

Check warning on line 35 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (Optiqor)
- [FAQ](#faq)
- [Contributing](#contributing)
- [License](#license)

---

## Why Optiqor CLI

Check warning on line 42 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (Optiqor)

Most Kubernetes cost tools require you to install an agent in your cluster, expose Prometheus, and wait 30 days for data. That is the right call for production teams who need exact numbers.

But sometimes you just want a directional answer **right now** about a chart you are reviewing.

The Optiqor CLI is a deterministic rule engine that reads your Helm chart files (or `values.yaml`) and reports cost inefficiencies in seconds. It runs fully offline. It does not phone home. It is honest about what it can and cannot tell from static files alone.

Check warning on line 48 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (Optiqor)

> [!TIP]
> **Bonus:** while it is parsing your chart for cost waste, it also flags the obvious Kubernetes security misconfigurations it sees (`runAsRoot`, `:latest` tags, missing `securityContext`, host namespaces, etc.). This is a side-effect of the parser — not the headline feature. If you need a real security posture tool, use one. If you happen to also catch them for free during a cost review, even better.
Expand All @@ -60,13 +60,13 @@
### Option 1: npx (zero-install, recommended for one-off use)

```sh
npx @optiqor/cli analyze ./chart

Check warning on line 63 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (optiqor)
```

### Option 2: Global npm install

```sh
npm install -g @optiqor/cli

Check warning on line 69 in README.md

View workflow job for this annotation

GitHub Actions / Spell check

Unknown word (optiqor)
optiqor analyze ./chart
```

Expand All @@ -87,7 +87,7 @@
```

> [!TIP]
> All release artifacts are signed with [Cosign](https://docs.sigstore.dev/cosign/overview/). Verification instructions on the [release page](https://github.com/optiqor/optiqor-cli/releases).
> All release artifacts are signed with [Cosign](https://github.com/sigstore/cosign). Verification instructions on the [release page](https://github.com/optiqor/optiqor-cli/releases).

### Option 5: Build from source

Expand Down Expand Up @@ -440,7 +440,7 @@
| Flag | Default | Description |
| --- | --- | --- |
| `--json` | false | Emit machine-readable JSON |
| `--offline` | true | Do not perform any network calls |
| `--offline` | false | Block opt-in network calls such as `--share` |
| `--share` | false | Upload sanitized analysis to optiqor.dev (opt-in) |
| `--no-color` | false | Disable ANSI color in output |
| `--quiet` | false | Suppress all output except findings |
Expand All @@ -453,8 +453,8 @@
| Variable | Purpose |
| --- | --- |
| `OPTIQOR_NO_COLOR` | Disable color output (CI-friendly, equivalent to `--no-color`) |
| `OPTIQOR_OFFLINE` | Force offline mode |
| `OPTIQOR_SHARE_BASE_URL` | Override the share endpoint (for self-hosted Optiqor) |
| `OPTIQOR_OFFLINE` | Set to `1`, `true`, `yes`, or `on` to force offline mode |
| `OPTIQOR_SHARE_URL` | Override the share endpoint (for self-hosted Optiqor) |
| `OPTIQOR_SKIP_POSTINSTALL` | Skip the npm postinstall binary download (for offline npm caches) |

---
Expand Down
29 changes: 24 additions & 5 deletions cmd/optiqor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"io"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -201,16 +202,19 @@ side-effect of parsing — they are not the headline feature.
return err
}
if shareFlag {
emitShareURL(cmd, rep)
if offlineMode(offline) {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "warning: --share is ignored in --offline mode")
} else {
emitShareURL(cmd, rep)
}
}
_ = offline
return checkFailOn(rep, effFailOn)
},
}
cmd.Flags().BoolVar(&jsonOut, "json", false, "emit machine-readable JSON")
cmd.Flags().StringVar(&htmlPath, "html", "", "also write a self-contained HTML report to this path")
cmd.Flags().BoolVar(&offline, "offline", true, "do not perform any network calls (always true in Phase 1)")
cmd.Flags().BoolVar(&shareFlag, "share", false, "print optiqor.dev/r/<hash> for the sanitised analysis (no upload in Phase 1)")
cmd.Flags().BoolVar(&offline, "offline", false, "block opt-in network calls such as --share (also: OPTIQOR_OFFLINE=1)")
cmd.Flags().BoolVar(&shareFlag, "share", false, "upload sanitised analysis and print optiqor.dev/r/<hash>")
cmd.Flags().BoolVar(&roast, "roast", false, "humorous output (findings stay accurate)")
cmd.Flags().StringVar(&minSev, "severity", "", "drop findings below this severity (low|med|high)")
cmd.Flags().StringArrayVar(&detectors, "detector", nil, "only run findings from these detector IDs (repeatable)")
Expand All @@ -228,7 +232,7 @@ func writeHTMLReport(path string, rep render.Report) error {
if err != nil {
return fmt.Errorf("open --html: %w", err)
}
defer f.Close()
defer func() { _ = f.Close() }()
return htmlrender.Render(f, htmlrender.Data{
Source: rep.Source,
Workloads: rep.Workloads,
Expand Down Expand Up @@ -334,6 +338,21 @@ func validSeverity(s rules.Severity) bool {
return s == rules.SeverityHigh || s == rules.SeverityMed || s == rules.SeverityLow
}

// offlineMode is the canonical egress gate. Any new network call in
// this binary must short-circuit when this returns true.
func offlineMode(flag bool) bool {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

worth a doc line saying this is the canonical egress gate. when watch or real audit add network calls they need to consult this too.

// offlineMode is the canonical egress gate. Any new network
// call in this binary MUST short-circuit when this returns true.
func offlineMode(flag bool) bool {

return flag || envTruthy("OPTIQOR_OFFLINE")
}

func envTruthy(name string) bool {
switch strings.ToLower(strings.TrimSpace(os.Getenv(name))) {
case "1", "true", "yes", "on":
return true
default:
return false
}
}

func toUpper(s string) string {
out := make([]byte, len(s))
for i := 0; i < len(s); i++ {
Expand Down
87 changes: 87 additions & 0 deletions cmd/optiqor/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"bytes"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
Expand Down Expand Up @@ -138,6 +140,91 @@ func TestAnalyze_JSONShape(t *testing.T) {
}
}

func TestAnalyze_OfflineShareWarnsAndSkipsUpload(t *testing.T) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nothing here asserts --share actually fires emitShareURL when offline's off. add a sibling that captures stderr and greps for share URL:. that branch is now load-bearing.

cmd := newRootCmd()
var out bytes.Buffer
var errBuf bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&errBuf)
cmd.SetArgs([]string{"analyze", "../../testdata/fixtures/basic-chart/values.yaml", "--offline", "--share"})
if err := cmd.Execute(); err != nil {
t.Fatalf("execute --offline --share: %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
if !strings.Contains(errBuf.String(), "warning: --share is ignored in --offline mode") {
t.Fatalf("missing offline share warning:\n%s", errBuf.String())
}
if strings.Contains(errBuf.String(), "share URL:") {
t.Fatalf("offline share should not print share URL:\n%s", errBuf.String())
}
}

func TestAnalyze_ShareUploadsWhenOfflineDisabled(t *testing.T) {
shareServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("share upload method = %s, want POST", r.Method)
}
if r.Header.Get("X-Optiqor-Hash") == "" {
t.Error("share upload missing X-Optiqor-Hash header")
}
w.WriteHeader(http.StatusNoContent)
}))
t.Cleanup(shareServer.Close)
t.Setenv("OPTIQOR_SHARE_URL", shareServer.URL)

cmd := newRootCmd()
var out bytes.Buffer
var errBuf bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&errBuf)
cmd.SetArgs([]string{"analyze", "../../testdata/fixtures/basic-chart/values.yaml", "--share"})
if err := cmd.Execute(); err != nil {
t.Fatalf("execute --share: %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
if strings.Contains(errBuf.String(), "warning: --share is ignored in --offline mode") {
t.Fatalf("online share should not warn about offline mode:\n%s", errBuf.String())
}
if !strings.Contains(errBuf.String(), "share URL:") {
t.Fatalf("online share should print share URL:\n%s", errBuf.String())
}
if !strings.Contains(errBuf.String(), "(uploaded)") {
t.Fatalf("online share should report upload success:\n%s", errBuf.String())
}
}

func TestAnalyze_OfflineEnvShareWarnsAndSkipsUpload(t *testing.T) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

right now nothing proves env beats an explicit --offline=false. add a variant with --offline=false --share and OPTIQOR_OFFLINE=1 set, assert the warning still fires.

t.Setenv("OPTIQOR_OFFLINE", "1")
cmd := newRootCmd()
var out bytes.Buffer
var errBuf bytes.Buffer
cmd.SetOut(&out)
cmd.SetErr(&errBuf)
cmd.SetArgs([]string{"analyze", "../../testdata/fixtures/basic-chart/values.yaml", "--offline=false", "--share"})
if err := cmd.Execute(); err != nil {
t.Fatalf("execute OPTIQOR_OFFLINE=1 --offline=false --share: %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
if !strings.Contains(errBuf.String(), "warning: --share is ignored in --offline mode") {
t.Fatalf("missing env offline share warning:\n%s", errBuf.String())
}
if strings.Contains(errBuf.String(), "share URL:") {
t.Fatalf("offline env share should not print share URL:\n%s", errBuf.String())
}
}

func TestAnalyze_HelpDocumentsOfflineEnv(t *testing.T) {
cmd := newRootCmd()
var buf bytes.Buffer
cmd.SetOut(&buf)
cmd.SetArgs([]string{"analyze", "--help"})
if err := cmd.Execute(); err != nil {
t.Fatalf("execute analyze --help: %v", err)
}
for _, want := range []string{"--offline", "OPTIQOR_OFFLINE=1", "--share"} {
if !strings.Contains(buf.String(), want) {
t.Errorf("analyze help missing %q:\n%s", want, buf.String())
}
}
}

func TestResolveColor_NoColorFlag(t *testing.T) {
cmd := newRootCmd()
if got := resolveColor(cmd, true); got {
Expand Down
4 changes: 4 additions & 0 deletions pkg/htmlrender/htmlrender.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ const AccuracyDisclosure = "Sandbox accuracy: ±40%. Install the Optiqor agent f
type Mode int

const (
// ModeSandbox renders the public, ±40%-accuracy sandbox banner used by
// the CLI and the optiqor.com share preview.
ModeSandbox Mode = iota
// ModeAgent renders the exact-accuracy banner used by the paid
// in-cluster agent path.
ModeAgent
)

Expand Down
4 changes: 2 additions & 2 deletions verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ for flag in --json --no-color --severity --fail-on --detector --config --offline
bash -c "'$BIN' analyze --help 2>&1 | grep -q -- '$flag'"
done

check "--offline defaults to true (zero-config never phones home)" \
bash -c "'$BIN' analyze --help 2>&1 | grep -qE 'offline.*default.*true'"
check "--offline documents the env override" \
bash -c "'$BIN' analyze --help 2>&1 | grep -q -- '--offline' && '$BIN' analyze --help 2>&1 | grep -q 'OPTIQOR_OFFLINE=1'"
check "--share is OFF by default" \
bash -c "'$BIN' analyze --help 2>&1 | grep -q -- '--share' && ! '$BIN' analyze --help 2>&1 | grep -qE 'share.*default *true'"

Expand Down
Loading