Skip to content

feat(types): validate snapshot name length and shape#61

Merged
CMGS merged 1 commit into
masterfrom
feat/snapshot-name-validate
May 20, 2026
Merged

feat(types): validate snapshot name length and shape#61
CMGS merged 1 commit into
masterfrom
feat/snapshot-name-validate

Conversation

@CMGS
Copy link
Copy Markdown
Contributor

@CMGS CMGS commented May 20, 2026

Summary

`cocoon snapshot save`/`import` previously accepted any string for `--name` — no length cap, no charset check. A snapshot named with 100+ chars or shell-unsafe chars would write straight into the DB, the OCI annotation on push, and any downstream propagation (Linux `HOST_NAME_MAX=64`, K8s DNS-1123 labels in pod name concatenation, etc).

This PR closes the gap by mirroring `VMConfig.Validate`'s rule on `SnapshotConfig`:

```go
validName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$`)
```

(1 leading char + ≤62 trailing = max 63 chars, fitting under Linux's HOST_NAME_MAX boundary.)

Changes

File Change
`types/snapshot.go` New `SnapshotConfig.Validate()` method (empty Name still allowed)
`types/snapshot_test.go` 9 subtests covering empty / valid / over-63 / leading-hyphen / space / slash / control char
`cmd/snapshot/handler.go` `Save` + `Import` validate the `--name` flag early — fail before expensive snapshot/import work
`snapshot/localfile/localfile.go` `Create` runs Validate before insert (defense-in-depth)
`snapshot/localfile/import.go` `Import` runs Validate after envelope/override merge

Behavior

Before:
```
$ cocoon snapshot save vm --name "my-very-very-long-name-that-keeps-going-and-going-and-blows-past-63-chars"
snapshot saved: ULID... # silently OK, downstream breaks later
```

After:
```
$ cocoon snapshot save vm --name "my-very-very-long-name-...-blows-past-63-chars"
Error: snapshot name "my-very..." is invalid: must match ^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$ (max 63 chars)
```

Same for `cocoon snapshot import --name X`.

Empty `--name` is still allowed (name is optional, ID is the fallback identifier).

Why

Reported by @doge: CH-bound hostname (set via cloud-init cidata or kernel cmdline) hits Linux `HOST_NAME_MAX=64` boundary. When vk-cocoon concatenates pod names → `cocoon snapshot save --name `, an overly long name would have been silently accepted, then surface as a downstream failure. `VMConfig` already validated this; SnapshotConfig didn't.

Verification

```
✓ go build ./...
✓ make lint (0 issues × Linux + Darwin)
✓ go test ./... (all green; 9 new SnapshotConfig.Validate subtests pass)
```

Test plan

  • `cocoon snapshot save vm --name foo` works
  • `cocoon snapshot save vm --name $(python -c 'print("a"*64)')` rejected with clear error
  • `cocoon snapshot save vm --name 'has space'` rejected
  • `cocoon snapshot save vm` (no `--name`) works (empty allowed)
  • `cocoon snapshot import file.tar.gz --name bad$char` rejected before opening file

cocoon snapshot save/import previously accepted any string for --name.
A snapshot named with 100 chars or shell-unsafe chars would write
straight into the DB / OCI annotation / cidata propagation chain,
breaking downstream consumers (Linux HOST_NAME_MAX=64, DNS-1123
labels, etc.).

Mirror VMConfig.Validate's `^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$` regex
on SnapshotConfig:

- types.SnapshotConfig.Validate() enforces ≤63 chars + safe charset
  (empty Name still allowed — name is optional for snapshots).
- cmd/snapshot/handler.go Save+Import validate the --name flag early
  to fail before the expensive snapshot/import operation.
- snapshot/localfile Create+Import call Validate as defense-in-depth
  so programmatic callers (vk-cocoon, future API) can't bypass.

Empty name remains valid (existing behavior — auto-generated ID is
the fallback identifier).
@CMGS CMGS merged commit 7d9b3dc into master May 20, 2026
4 checks passed
@CMGS CMGS deleted the feat/snapshot-name-validate branch May 20, 2026 10:48
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.

1 participant