Skip to content

Validation gaps, dead code and duplication: name ≤19 TODO, ParseLabels, IPv6 forward, unreachable helpers, two upload FS resolvers, gitignore over-exclusion #20

Description

@clcollins

Type: Low-severity cleanup, batched so it can be one PR.

Validation gaps

  • No client-side sandbox name ≤ 19 check despite the TODO at internal/cli/sandbox.go:16 and the gateway's name exceeds maximum length (20 > 19) error being known (divergence log line 1274).
  • ParseLabels accepts empty keys while v1alpha1.Validate rejects them; sessionOpts.forward is unvalidated in Validate; deprecated flat fields + sessionOpts both set → new wins silently (warn); validate.go:85-91 workspace check is effectively dead.
  • ValidateCPU accepts Go-only forms (0x1p4, +2) the Rust CLI would reject.
  • ParseForwardSpec rejects [::1]:80-style IPv6 (bind becomes [::1] and is accepted verbatim).
  • namesFromManifest (internal/cli/sandbox_lifecycle.go:122-131) returns a slice but callers take names[0] (sandbox_cmd.go:68) — a multi-document manifest is silently truncated to the first document. Decision: error on more than one document for every command except create/delete (which may apply all), matching kubectl semantics; test both. (Policy multi-doc handling: item 25.)

Dead / contradictory code

  • notImplementedLeaf (internal/cli/sandbox.go:57) unused; the keep field (internal/cli/sandbox_create.go:224, populated at :68) is never read; SkipProviderMessage (pkg/sandbox/providers.go:146) never called though pkg/sandbox/create.go:224 says a message is printed; readAll/bytesReader (internal/cli/sandbox_create.go:26-27) are one-line wrappers over io.ReadAll/bytes.NewReader; pkg/policyyaml/serialize.go:197 reimplements strings.IndexByte. (bidiStream.cancel is owned by item 7; the stale create.go:16-19 comments by item 2.)
  • Upload's last_sandbox fallback (internal/cli/sandbox_transfer.go:34) is unreachable because parseUploadArgs errors on one arg despite RangeArgs(1,3) — either make one-arg upload work (NAME from last_sandbox) or tighten to RangeArgs(2,3).

Duplication hurting maintainability

  • withGatewayTarget / workspace() / resolveNameFromFileOrArgs / saveLastSandbox boilerplate copied across ten commands (a runWithSandbox helper — item 1 — fixes the -f ordering bug in one place).
  • Two upload FS resolvers with different semantics: runCreateUploads (internal/cli/sandbox_create.go) roots transfer.OSFS at /, the upload subcommand (resolveUploadFS, sandbox_transfer.go) at cwd, so findRepoRoot (pkg/transfer/gitignore.go:63) can find an enclosing .git in one path and not the other. Use one resolver.
  • envKeyRe duplicated in pkg/api/v1alpha1/validate.go:68 and pkg/sandbox/envlabel.go:10; WatchUntilReady (pkg/sandbox/watch.go:89) vs watchUntilPhase (pkg/sandbox/lifecycle.go:64) overlap; two raw-mode/SIGWINCH stacks (item 15).

gitignore / tar minor

  • pkg/transfer/gitignore.go:126-147: a nested non-anchored pattern with an inner slash (build/out in sub/.gitignore) is rewritten to sub/**/build/out, and go-gitignore prefixes ^(|.*/), so it matches at any depth (over-exclusion). No directory pruning, so ! can re-include under an excluded dir (git cannot). Expected semantics (git): a pattern containing a slash is anchored to the directory of the .gitignore that contains it (sub/build/out only), and once a directory is excluded nothing beneath it can be re-included. Implement those two rules; if the "gitignore-compatible, not git-index-identical" caveat (plan Decision 8) is kept, document these specific deviations in README.
  • Upload tar headers carry local uid/gid/uname (pkg/transfer/tar.go:45,61) — normalise to 0/root or the sandbox user.
  • clampU16 (pkg/policyyaml/serialize.go:206) silently clamps ports > 65535 instead of erroring.

Acceptance

Each fixed item has a unit test; dead symbols deleted (not commented out); golangci-lint unused passes.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions