-
Notifications
You must be signed in to change notification settings - Fork 0
Release develop → main #397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
f09078a
fix(delete): verify the host-data wipe before printing ✔ (RFC-0003) (…
saadqbal dfee738
feat(cli): auto-update — nudge + tracebloc upgrade (F1) (#390)
LukasWodka 27fd92a
fix(push): defer progress-bar first render until bytes flow (#391)
LukasWodka 5ed2f63
feat(install): prefer ~/bin when already on PATH (B2, RFC 0001) (#392)
LukasWodka 71ed489
feat(cli): tracebloc prepare-host wrapper (#1178, cli) (#394)
LukasWodka 234d8fe
feat(status): surface the environment's seal-check verdict (client st…
LukasWodka a242f46
docs(rfc): RFC-0003 — dataset storage & offboard hygiene (draft) (#366)
LukasWodka 1856c90
fix: resolve Bugbot findings on promotion PR #397 (#402)
shujaatTracebloc 4ecca9a
fix(resources): clamp wizard defaults into their own valid range (#39…
LukasWodka fcdefca
fix: Bugbot findings from promotion PR #397 (TLS floor + delete cache…
shujaatTracebloc 6548218
fix(doctor): per-OS compute remedies + resources-set-max drift nudge …
LukasWodka 327987b
fix(resources): 'equipped with' reports the largest node, not a cross…
LukasWodka a6baa17
fix: treat seal Ctrl-C as quiet interrupt, not false Unsealed (Bugbot…
shujaatTracebloc 12bbe7e
fix(home): adopt a LOCAL cluster's release when the client pointer is…
LukasWodka 550979a
fix(prompts): a cancelled prompt is never silent — one helper, exit 0…
LukasWodka b766f39
docs(bugbot): add .cursor/BUGBOT.md project context (backend#930) (#409)
LukasWodka 292116e
docs(pr-template): owner-qualify cross-repo closing keywords (tracebl…
LukasWodka 25db81d
docs(rfc): state qualified identifiers in the RFC headers (#412)
LukasWodka 19ea73f
fix: skip update check (not just cache write) when config dir is abse…
shujaatTracebloc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| # Bugbot guide — tracebloc/cli | ||
|
|
||
| ## Context | ||
|
|
||
| Public Go CLI (Apache-2.0), shipped as **signed 8-platform releases** (cosign keyless, | ||
| verified by `scripts/install.sh`). Customers run it on their own machines against their own | ||
| Kubernetes to operate a self-hosted secure environment. It talks to a public HTTPS backend | ||
| (`internal/api`) and to an in-cluster jobs-manager (`internal/submit`), and shells out to | ||
| `kubectl`/`helm`/`docker`. | ||
|
|
||
| Two things make this repo unusual and should shape every finding: | ||
|
|
||
| 1. **Its exit codes are a scripting contract** — customers branch on them | ||
| (`internal/cli/exitcodes.go`: "the numeric values are FROZEN"). | ||
| 2. **`make ci` mirrors CI exactly.** The `Makefile` header states it outright: "divergence | ||
| between local and CI is the bug this file exists to prevent." Tool versions are pinned in | ||
| lockstep with `.github/workflows/build.yml`. | ||
|
|
||
| ## Always flag | ||
|
|
||
| - **A command that reports success it hasn't earned.** Exiting 0 is not the same as | ||
| succeeding. The reference pattern is `classifyPushOutcome` | ||
| (`internal/cli/data_ingest_output.go:25`): a Job that exits 0 but whose summary reports row | ||
| failures returns `"completed_with_failures"` + `exitIngestFailed`, *not* `"succeeded"` — its | ||
| comment cites this class explicitly. `internal/doctor` carries the same idea in | ||
| `StatusUnknown`: a check that ran but cannot back a green prints a neutral line rather than a | ||
| false ✔. Flag any new multi-step command where a partial failure collapses into success, and | ||
| any path where the `--output-json` status and the process exit code can disagree. | ||
|
|
||
| - **An exit code that isn't a named constant from `internal/cli/exitcodes.go`**, a repurposed | ||
| numeric value, or a new failure path returning generic `1` when a specific code already | ||
| exists. Every non-test `&exitError{}` names its code. | ||
|
|
||
| - **A prompt whose cancellation produces no visible feedback.** `errInteractiveCancelled` | ||
| (`internal/cli/interactive.go:26`) must print a `Cancelled — …` line via the Printer and then | ||
| return cleanly — see `resources_set.go:219`, `data_delete.go:233`, | ||
| `data_ingest_local.go:103`, `data_ingest_cluster.go:339`. Watch for | ||
| **`mapClientErr` (`internal/cli/client.go:858`), which maps it straight to `nil` with no | ||
| output at all** — a Ctrl-C routed through it exits 0 in total silence, right next to a | ||
| declined-answer branch that *does* print (`client.go:334`, `delete.go:196`). Check this at | ||
| every new or changed prompt site. Signals are wired centrally via `signal.NotifyContext` | ||
| (`cmd/tracebloc/main.go:58`) so deferred cleanup runs — a bare handler skips it and breaks | ||
| `push.Stage`'s cleanup contract. Interrupted-but-clean paths exit 130. | ||
|
|
||
| - **HTTP 426 treated as anything other than a hard stop.** It is detected centrally | ||
| (`internal/api/client.go`, `parseUpgradeRequired` → `*UpgradeRequiredError`) so every caller | ||
| degrades to the same actionable "run `tracebloc upgrade`" message — see `auth.go:336`, | ||
| `doctor.go:119`, `client_status.go:129`, `delete.go:151,218`, `client.go:253`. Flag a new API | ||
| consumer that retries through it, frames it as a transient outage, or folds it into a generic | ||
| error. A too-old CLI never recovers by waiting, so `--wait` loops must fail fast on it. | ||
|
|
||
| - **Verification that degrades to a warning.** In `scripts/install.sh` the SHA256 compare | ||
| aborts when no hashing tool is present, and `verify_cosign_signature()` bootstraps a pinned, | ||
| checksum-verified cosign (`COSIGN_VERSION=v2.4.1`) rather than skipping; the only bypass is an | ||
| explicit `TRACEBLOC_ALLOW_UNVERIFIED=1` with a loud warning. A previous "warn + continue + | ||
| still print ✓ matches" branch was caught as *both* a security regression and a dishonest log. | ||
| Also flag any `--version` / `RELEASE_VERSION` use that skips `validate_version_tag` before URL | ||
| interpolation. `tracebloc upgrade` and host prep must keep delegating to this verified script | ||
| instead of reimplementing verification in Go. | ||
|
|
||
| - **An external call with no ceiling.** Backend HTTP: `defaultTimeout = 30 * time.Second` | ||
| (`internal/api/client.go:31`). In-cluster submit: `SubmitTimeout` | ||
| (`internal/submit/client.go:21`). Doctor probes: `httpProbeTimeout = 8s`. Every shell-out uses | ||
| `exec.CommandContext`. Flag a bare `exec.Command` in non-test code, an `http.Client{}` with no | ||
| `Timeout`, or a watch/poll loop with no deadline. | ||
|
|
||
| - **A missing empty / nil / zero guard on anything crossing a boundary** (user input, API | ||
| response, cluster state). There is no shared validator — the convention is a colocated | ||
| `validate*` func: `internal/push/spec.go:100` (`ValidateTableName`), | ||
| `internal/cli/interactive.go:537-568`. Two specifics: a bare Enter yields `""` and must not be | ||
| treated as a real path (`validateDatasetPath` documents exactly this); and pagination must | ||
| fail loudly on an unparseable `next` link rather than silently truncating the list | ||
| (`internal/api/client.go`, `nextPath`). Where "empty" and "unknown" are different answers, | ||
| prefer a three-valued return (`internal/cluster/discover.go:302`). | ||
|
|
||
| - **A cross-repo contract change that only lands on one side.** `scripts/.data-ingestors-ref`, | ||
| `scripts/.client-ref` and `scripts/.backend-ref` pin upstream refs deliberately so an | ||
| unrelated upstream commit can't red every open PR. Flag a hand-edit to a generated artifact | ||
| (`internal/schema/*.json`, `internal/api/testdata/*.json`, | ||
| `internal/push/testdata/parity/goldens.json`, `internal/cli/testdata/golden/*.golden`) that | ||
| doesn't also bump and re-sync its pin, and any change to a chart assumption (discovery labels, | ||
| jobs-manager port, PVC mount path) that doesn't update `scripts/chart-invariants` — a chart | ||
| rename otherwise ships green in both repos and breaks discovery in the field. | ||
|
|
||
| - **Output that breaks the style contract** (`STYLE.md`): all colour goes through | ||
| `internal/ui`'s Printer — never inline an escape or brand hex outside `internal/ui` | ||
| (`scripts/check-style.sh` greps for it). Colour is never load-bearing: headings carry bold, | ||
| alerts carry a glyph, so the output still reads under `NO_COLOR`, in a pipe, and for a | ||
| colour-blind reader. User-facing copy follows the terminology table ("secure environment", | ||
| "ingest", "delete", "Online/Offline", "collaborators", "task"); only the workspace → secure | ||
| environment swap is grep-enforced, the rest is review judgement. A new user-facing string | ||
| almost always needs its golden regenerated: | ||
| `TB_UPDATE_GOLDEN=1 go test ./internal/cli/ -run TestCopyCatalog`. | ||
|
|
||
| - **Errors that lose their type.** `%w` wrapping is the house convention (~325 sites), with | ||
| typed errors for the cases callers branch on: `APIError`, `UpgradeRequiredError`, | ||
| `SubmitError`, `WatchError`, `exitError`, `noParentReleaseError`. Flag string-matching on an | ||
| error message where `errors.Is`/`errors.As` applies. | ||
|
|
||
| ## Known non-issues — do not flag | ||
|
|
||
| - **`.golangci.yml` does not gate CI.** `golangci-lint` is never invoked in a workflow (its | ||
| `staticcheck`/`unused` are disabled there for runner OOM reasons); the blocking Lint job runs | ||
| pinned standalone binaries — `errcheck`, `gofmt -s`, `goimports`, `ineffassign`, `misspell`, | ||
| `staticcheck`, plus `deadcode-check.sh`, `file-budget.sh`, `check-style.sh`. Don't infer | ||
| coverage from that file. | ||
| - **`staticcheck` runs `-checks all,-ST1005` deliberately** — do not flag error-string | ||
| capitalisation or punctuation. It is a tracked, intentional exclusion (cli#279). | ||
| - `internal/submit/client.go:78` — `InsecureSkipVerify` is intentional for cluster-internal | ||
| traffic with no recognisable CA, documented in place and marked `//nolint:gosec`. It is the | ||
| only `nolint` in the repo. | ||
| - `scripts/deadcode-allowlist.txt` entries are verified false positives (Stringers reached only | ||
| through `fmt` reflection; test-only parity harnesses that must live in production source). | ||
| - `test/integration/*` uses 30s–5min timeouts because it drives a real cluster — not the | ||
| production timeout convention. | ||
| - `mutation.yml` and `head-drift-canary.yml` are advisory and never gate a merge. | ||
| - No `vendor/` directory — the module cache is used on purpose. | ||
| - `// style-guard: allow` is a defined escape hatch but is currently used nowhere; if one | ||
| appears, it is a novel exception worth scrutiny rather than an accepted pattern. | ||
|
|
||
| ## Tone | ||
|
|
||
| Direct. Name the file and line. Give a concrete fix, not "consider". State the customer-visible | ||
| consequence — what they see, and which exit code they get — not just the code smell. | ||
|
|
||
| This repo is **public**: never put a customer name, internal hostname, or internal-only ticket | ||
| detail in a finding. A bare `tracebloc/backend#NNNN` reference is fine. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.