detached 20864cb

refactor(snapshot): simplify publication validation

commit
20864cba18d8139199f3f7c7402e3819cb161be8
author
brice · · 2026-07-21 20:29 UTC
parent
13c7e30
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +12 -13
M internal/adapters/snapshot/publish.go +11 -12
@@ -18,11 +18,10 @@ func (r *Repository) Publish(ctx context.Context, publication ports.SnapshotPubl
1818 lock.Lock()
1919 defer lock.Unlock()
2020
21- manifest, refs, supplied, err := validatePublication(publication)
21+ refs, supplied, err := validatePublication(publication)
2222 if err != nil {
2323 return err
2424 }
25- _ = manifest
2625 if err := r.ensureSession(key); err != nil {
2726 return err
2827 }
@@ -106,40 +105,40 @@ func (r *Repository) Publish(ctx context.Context, publication ports.SnapshotPubl
106105 }
107106 return nil
108107 }
109-func validatePublication(p ports.SnapshotPublication) (codec.Manifest, map[ports.SnapshotDigest]codec.ObjectRef, map[ports.SnapshotDigest]ports.SnapshotObject, error) {
108+func validatePublication(p ports.SnapshotPublication) (map[ports.SnapshotDigest]codec.ObjectRef, map[ports.SnapshotDigest]ports.SnapshotObject, error) {
110109 manifest, err := codec.UnmarshalManifest(p.Manifest)
111110 if err != nil {
112- return codec.Manifest{}, nil, nil, fmt.Errorf("invalid manifest: %w", err)
111+ return nil, nil, fmt.Errorf("invalid manifest: %w", err)
113112 }
114113 if manifest.Name != p.Name || manifest.Generation != p.Generation || p.Generation == 0 {
115- return codec.Manifest{}, nil, nil, fmt.Errorf("manifest name or generation does not match publication")
114+ return nil, nil, fmt.Errorf("manifest name or generation does not match publication")
116115 }
117116 refs := manifestRefs(manifest)
118117 if refs == nil {
119- return codec.Manifest{}, nil, nil, fmt.Errorf("conflicting manifest references")
118+ return nil, nil, fmt.Errorf("conflicting manifest references")
120119 }
121120 if !withinGenerationBudget(len(p.Manifest), refs) {
122- return codec.Manifest{}, nil, nil, fmt.Errorf("snapshot generation too large")
121+ return nil, nil, fmt.Errorf("snapshot generation too large")
123122 }
124123 objects := make(map[ports.SnapshotDigest]ports.SnapshotObject, len(p.Objects))
125124 for _, object := range p.Objects {
126125 if sha256.Sum256(object.Data) != object.Digest {
127- return codec.Manifest{}, nil, nil, fmt.Errorf("object digest mismatch")
126+ return nil, nil, fmt.Errorf("object digest mismatch")
128127 }
129128 ref, used := refs[object.Digest]
130129 if !used {
131- return codec.Manifest{}, nil, nil, fmt.Errorf("unreferenced object")
130+ return nil, nil, fmt.Errorf("unreferenced object")
132131 }
133132 kind, payload, err := codec.PreflightObject(object.Data)
134133 if err != nil || kind != ref.Kind || len(object.Data) != int(ref.Size) || len(payload) == 0 {
135- return codec.Manifest{}, nil, nil, fmt.Errorf("invalid object envelope")
134+ return nil, nil, fmt.Errorf("invalid object envelope")
136135 }
137136 if old, duplicate := objects[object.Digest]; duplicate && !equalBytes(old.Data, object.Data) {
138- return codec.Manifest{}, nil, nil, fmt.Errorf("conflicting object")
137+ return nil, nil, fmt.Errorf("conflicting object")
139138 }
140139 objects[object.Digest] = ports.SnapshotObject{Digest: object.Digest, Data: append([]byte(nil), object.Data...)}
141140 }
142- return manifest, refs, objects, nil
141+ return refs, objects, nil
143142 }
144143
145144 func withinGenerationBudget(manifestSize int, refs map[ports.SnapshotDigest]codec.ObjectRef) bool {
@@ -18,11 +18,10 @@ func (r *Repository) Publish(ctx context.Context, publication ports.SnapshotPubl
18 lock.Lock()18 lock.Lock()
19 defer lock.Unlock()19 defer lock.Unlock()
20 20
21- manifest, refs, supplied, err := validatePublication(publication)21+ refs, supplied, err := validatePublication(publication)
22 if err != nil {22 if err != nil {
23 return err23 return err
24 }24 }
25- _ = manifest
26 if err := r.ensureSession(key); err != nil {25 if err := r.ensureSession(key); err != nil {
27 return err26 return err
28 }27 }
@@ -106,40 +105,40 @@ func (r *Repository) Publish(ctx context.Context, publication ports.SnapshotPubl
106 }105 }
107 return nil106 return nil
108 }107 }
109-func validatePublication(p ports.SnapshotPublication) (codec.Manifest, map[ports.SnapshotDigest]codec.ObjectRef, map[ports.SnapshotDigest]ports.SnapshotObject, error) {108+func validatePublication(p ports.SnapshotPublication) (map[ports.SnapshotDigest]codec.ObjectRef, map[ports.SnapshotDigest]ports.SnapshotObject, error) {
110 manifest, err := codec.UnmarshalManifest(p.Manifest)109 manifest, err := codec.UnmarshalManifest(p.Manifest)
111 if err != nil {110 if err != nil {
112- return codec.Manifest{}, nil, nil, fmt.Errorf("invalid manifest: %w", err)111+ return nil, nil, fmt.Errorf("invalid manifest: %w", err)
113 }112 }
114 if manifest.Name != p.Name || manifest.Generation != p.Generation || p.Generation == 0 {113 if manifest.Name != p.Name || manifest.Generation != p.Generation || p.Generation == 0 {
115- return codec.Manifest{}, nil, nil, fmt.Errorf("manifest name or generation does not match publication")114+ return nil, nil, fmt.Errorf("manifest name or generation does not match publication")
116 }115 }
117 refs := manifestRefs(manifest)116 refs := manifestRefs(manifest)
118 if refs == nil {117 if refs == nil {
119- return codec.Manifest{}, nil, nil, fmt.Errorf("conflicting manifest references")118+ return nil, nil, fmt.Errorf("conflicting manifest references")
120 }119 }
121 if !withinGenerationBudget(len(p.Manifest), refs) {120 if !withinGenerationBudget(len(p.Manifest), refs) {
122- return codec.Manifest{}, nil, nil, fmt.Errorf("snapshot generation too large")121+ return nil, nil, fmt.Errorf("snapshot generation too large")
123 }122 }
124 objects := make(map[ports.SnapshotDigest]ports.SnapshotObject, len(p.Objects))123 objects := make(map[ports.SnapshotDigest]ports.SnapshotObject, len(p.Objects))
125 for _, object := range p.Objects {124 for _, object := range p.Objects {
126 if sha256.Sum256(object.Data) != object.Digest {125 if sha256.Sum256(object.Data) != object.Digest {
127- return codec.Manifest{}, nil, nil, fmt.Errorf("object digest mismatch")126+ return nil, nil, fmt.Errorf("object digest mismatch")
128 }127 }
129 ref, used := refs[object.Digest]128 ref, used := refs[object.Digest]
130 if !used {129 if !used {
131- return codec.Manifest{}, nil, nil, fmt.Errorf("unreferenced object")130+ return nil, nil, fmt.Errorf("unreferenced object")
132 }131 }
133 kind, payload, err := codec.PreflightObject(object.Data)132 kind, payload, err := codec.PreflightObject(object.Data)
134 if err != nil || kind != ref.Kind || len(object.Data) != int(ref.Size) || len(payload) == 0 {133 if err != nil || kind != ref.Kind || len(object.Data) != int(ref.Size) || len(payload) == 0 {
135- return codec.Manifest{}, nil, nil, fmt.Errorf("invalid object envelope")134+ return nil, nil, fmt.Errorf("invalid object envelope")
136 }135 }
137 if old, duplicate := objects[object.Digest]; duplicate && !equalBytes(old.Data, object.Data) {136 if old, duplicate := objects[object.Digest]; duplicate && !equalBytes(old.Data, object.Data) {
138- return codec.Manifest{}, nil, nil, fmt.Errorf("conflicting object")137+ return nil, nil, fmt.Errorf("conflicting object")
139 }138 }
140 objects[object.Digest] = ports.SnapshotObject{Digest: object.Digest, Data: append([]byte(nil), object.Data...)}139 objects[object.Digest] = ports.SnapshotObject{Digest: object.Digest, Data: append([]byte(nil), object.Data...)}
141 }140 }
142- return manifest, refs, objects, nil141+ return refs, objects, nil
143 }142 }
144 143
145 func withinGenerationBudget(manifestSize int, refs map[ports.SnapshotDigest]codec.ObjectRef) bool {144 func withinGenerationBudget(manifestSize int, refs map[ports.SnapshotDigest]codec.ObjectRef) bool {
M internal/adapters/snapshot/repository_hardening_test.go +1 -1
@@ -75,7 +75,7 @@ func TestValidatePublicationRejectsUnloadableAggregate(t *testing.T) {
7575 t.Fatal(err)
7676 }
7777 pub.Objects = nil // validation permits omitted objects for immutable reuse.
78- if _, _, _, err := validatePublication(pub); err == nil {
78+ if _, _, err := validatePublication(pub); err == nil {
7979 t.Fatal("validatePublication accepted unloadable aggregate")
8080 } else if errors.Is(err, os.ErrNotExist) {
8181 t.Fatalf("validatePublication returned unrelated error: %v", err)
@@ -75,7 +75,7 @@ func TestValidatePublicationRejectsUnloadableAggregate(t *testing.T) {
75 t.Fatal(err)75 t.Fatal(err)
76 }76 }
77 pub.Objects = nil // validation permits omitted objects for immutable reuse.77 pub.Objects = nil // validation permits omitted objects for immutable reuse.
78- if _, _, _, err := validatePublication(pub); err == nil {78+ if _, _, err := validatePublication(pub); err == nil {
79 t.Fatal("validatePublication accepted unloadable aggregate")79 t.Fatal("validatePublication accepted unloadable aggregate")
80 } else if errors.Is(err, os.ErrNotExist) {80 } else if errors.Is(err, os.ErrNotExist) {
81 t.Fatalf("validatePublication returned unrelated error: %v", err)81 t.Fatalf("validatePublication returned unrelated error: %v", err)

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 12

Tags 11

↑↓ moveenter openesc close