v3.2.0 4fc01fa

image.go RawHistoryFolder

1package validation
2
3import (
4	"fmt"
5	"strings"
6)
7
8const sha256DigestLength = len("sha256:") + 64
9
10// ValidateImageDigest validates the only digest format accepted for image
11// references and resolved deployment pins: sha256 followed by exactly 64
12// lowercase hexadecimal characters.
13func ValidateImageDigest(digest string) error {
14	if len(digest) != sha256DigestLength || !strings.HasPrefix(digest, "sha256:") {
15		return fmt.Errorf("image digest must be sha256:<64 hex chars>")
16	}
17	for _, c := range digest[len("sha256:"):] {
18		if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
19			return fmt.Errorf("image digest must be sha256:<64 hex chars>")
20		}
21	}
22	return nil
23}
24
25// ParseImageReference parses an image reference into name and tag/digest.
26// Supports formats:
27//   - image:tag (default tag is "latest")
28//   - image@sha256:... (digest)
29//   - image (defaults to "latest")
30//   - registry.example.com/image:tag
31//   - registry.example.com/image@sha256:...
32//
33// Returns:
34//   - name: the image name (including registry if specified)
35//   - reference: the tag (e.g., "latest") or digest (e.g., "sha256:...")
36func ParseImageReference(imageRef string) (string, string) {
37	// Check for digest reference (@sha256:...)
38	if idx := strings.Index(imageRef, "@sha256:"); idx != -1 {
39		return imageRef[:idx], imageRef[idx+1:] // Return name and full digest
40	}
41
42	// Check for tag reference (:tag)
43	if idx := strings.Index(imageRef, ":"); idx != -1 {
44		// Check if this is actually a port number (e.g., registry:5000/image)
45		// by looking for a slash before the colon
46		if slashIdx := strings.Index(imageRef, "/"); slashIdx != -1 && slashIdx > idx {
47			// Slash comes after colon, so colon is part of registry port
48			// Look for another colon for the tag
49			if tagIdx := strings.Index(imageRef[slashIdx:], ":"); tagIdx != -1 {
50				actualTagIdx := slashIdx + tagIdx
51				return imageRef[:actualTagIdx], imageRef[actualTagIdx+1:]
52			}
53			return imageRef, "latest"
54		}
55		return imageRef[:idx], imageRef[idx+1:] // Return name and tag
56	}
57
58	// Default to "latest" tag
59	return imageRef, "latest"
60}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close