oficina / suite Public

Clone
git clone https://amadan.net/oficina/suite

Plain git — no account needed to clone.

Download

Download this file

1package suite
2
3import (
4 "errors"
5 "fmt"
6)
7
8// ErrNotAvailable is the whole vocabulary of an S3 refusal.
9//
10// Doctrine §4.2: a content fetch for anything outside the custody predicate
11// answers 404, never 403, and the status is identical for "not team-visible"
12// and "does not exist". Deleted, never team-visible, and departed from
13// team-visibility are one answer here on purpose — a consumer that could tell
14// them apart would learn that a private item exists.
15var ErrNotAvailable = errors.New("suite: item not available")
16
17// ErrContractBreach marks a sibling answering in a way the contract forbids.
18// It is separate from a refusal and from an outage because it is neither: it
19// is a bug in the sibling that a consumer should surface rather than absorb.
20var ErrContractBreach = errors.New("suite: sibling broke the contract")
21
22// DecodeS3 reads a content fetch. There is no asker anywhere in this call:
23// S3 is custody-scoped and person-less, and memoria's draft 3 added a person
24// to it, which both broke the ingest path — the warm-up, the rebuild and
25// derived-artefact regeneration have no asker — and pulled individually
26// granted rows into a store that may not hold them.
27func DecodeS3(status int, body []byte) ([]byte, error) {
28 switch {
29 case status >= 200 && status <= 299:
30 return body, nil
31
32 case status == 404:
33 return nil, ErrNotAvailable
34
35 case status == 403:
36 // "404, never 403" is the rule, because 403 means "this exists and
37 // you may not have it" — the one fact custody hides. A sibling
38 // answering 403 is leaking, and folding it into ErrNotAvailable would
39 // keep that leak invisible to everyone downstream.
40 return nil, fmt.Errorf("%w: S3 answered 403 where the contract requires 404", ErrContractBreach)
41
42 default:
43 return nil, fmt.Errorf("suite: S3 answered %d", status)
44 }
45}
46