Merge 8aa547e07ea278c9bb3e409a597c0899e2750235 into 70c00ad2d5a23676a0759d7ae2dcab5e5dcd4425
57 files · +51 -183
M go.mod +1 -1
| @@ -64,7 +64,7 @@ require ( | |||
| 64 | 64 | github.com/bep/godartsass/v2 v2.5.0 // indirect | |
| 65 | 65 | github.com/bep/golibsass v1.2.0 // indirect | |
| 66 | 66 | github.com/bits-and-blooms/bitset v1.24.5 // indirect | |
| 67 | - | github.com/bnema/hexcheck v0.3.1 // indirect | |
| 67 | + | github.com/bnema/hexcheck v0.4.0 // indirect | |
| 68 | 68 | github.com/brunoga/deep v1.3.1 // indirect | |
| 69 | 69 | github.com/bufbuild/buf v1.73.0 // indirect | |
| 70 | 70 | github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201 // indirect | |
| @@ -64,7 +64,7 @@ require ( | |||||
| 64 | github.com/bep/godartsass/v2 v2.5.0 // indirect | 64 | github.com/bep/godartsass/v2 v2.5.0 // indirect | ||
| 65 | github.com/bep/golibsass v1.2.0 // indirect | 65 | github.com/bep/golibsass v1.2.0 // indirect | ||
| 66 | github.com/bits-and-blooms/bitset v1.24.5 // indirect | 66 | github.com/bits-and-blooms/bitset v1.24.5 // indirect | ||
| 67 | - | github.com/bnema/hexcheck v0.3.1 // indirect | 67 | + | github.com/bnema/hexcheck v0.4.0 // indirect |
| 68 | github.com/brunoga/deep v1.3.1 // indirect | 68 | github.com/brunoga/deep v1.3.1 // indirect | ||
| 69 | github.com/bufbuild/buf v1.73.0 // indirect | 69 | github.com/bufbuild/buf v1.73.0 // indirect | ||
| 70 | github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201 // indirect | 70 | github.com/bufbuild/protocompile v0.14.2-0.20260910151042-7436f7c76201 // indirect | ||
M go.sum +2 -2
| @@ -108,8 +108,8 @@ github.com/bits-and-blooms/bitset v1.24.5 h1:654xBVHc23gJMAgOTkPNoCVfiRxuIOAUnAZ | |||
| 108 | 108 | github.com/bits-and-blooms/bitset v1.24.5/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= | |
| 109 | 109 | github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= | |
| 110 | 110 | github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= | |
| 111 | - | github.com/bnema/hexcheck v0.3.1 h1:Apv7w0KmsfbOBOq/r1jPlENX3Z7ukAEPlAxvWMTTd3I= | |
| 112 | - | github.com/bnema/hexcheck v0.3.1/go.mod h1:8KuFStFhn1qNKDBrUvxOB5VzSP/uuePrURqPhq2KVAk= | |
| 111 | + | github.com/bnema/hexcheck v0.4.0 h1:VwzikMw5uCRvyf+FcI+O67TXovw7iwqvn7dSOUCJs7c= | |
| 112 | + | github.com/bnema/hexcheck v0.4.0/go.mod h1:8KuFStFhn1qNKDBrUvxOB5VzSP/uuePrURqPhq2KVAk= | |
| 113 | 113 | github.com/bnema/kvconf v0.1.2 h1:1hDKL9jkQSBdR9dSKbwTONhUUBfJgAdh5vu+yFHOb70= | |
| 114 | 114 | github.com/bnema/kvconf v0.1.2/go.mod h1:+P2X9I/sLx+Lfir45s9a7WA0GnC22WgKbZWE9LK6lcU= | |
| 115 | 115 | github.com/bnema/zerowrap v1.4.1 h1:v70w8LDU2+FU+EX/etY9DjVwOAWN0fUKShwZyZHnyLU= | |
| @@ -108,8 +108,8 @@ github.com/bits-and-blooms/bitset v1.24.5 h1:654xBVHc23gJMAgOTkPNoCVfiRxuIOAUnAZ | |||||
| 108 | github.com/bits-and-blooms/bitset v1.24.5/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= | 108 | github.com/bits-and-blooms/bitset v1.24.5/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= | ||
| 109 | github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= | 109 | github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= | ||
| 110 | github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= | 110 | github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= | ||
| 111 | - | github.com/bnema/hexcheck v0.3.1 h1:Apv7w0KmsfbOBOq/r1jPlENX3Z7ukAEPlAxvWMTTd3I= | 111 | + | github.com/bnema/hexcheck v0.4.0 h1:VwzikMw5uCRvyf+FcI+O67TXovw7iwqvn7dSOUCJs7c= |
| 112 | - | github.com/bnema/hexcheck v0.3.1/go.mod h1:8KuFStFhn1qNKDBrUvxOB5VzSP/uuePrURqPhq2KVAk= | 112 | + | github.com/bnema/hexcheck v0.4.0/go.mod h1:8KuFStFhn1qNKDBrUvxOB5VzSP/uuePrURqPhq2KVAk= |
| 113 | github.com/bnema/kvconf v0.1.2 h1:1hDKL9jkQSBdR9dSKbwTONhUUBfJgAdh5vu+yFHOb70= | 113 | github.com/bnema/kvconf v0.1.2 h1:1hDKL9jkQSBdR9dSKbwTONhUUBfJgAdh5vu+yFHOb70= | ||
| 114 | github.com/bnema/kvconf v0.1.2/go.mod h1:+P2X9I/sLx+Lfir45s9a7WA0GnC22WgKbZWE9LK6lcU= | 114 | github.com/bnema/kvconf v0.1.2/go.mod h1:+P2X9I/sLx+Lfir45s9a7WA0GnC22WgKbZWE9LK6lcU= | ||
| 115 | github.com/bnema/zerowrap v1.4.1 h1:v70w8LDU2+FU+EX/etY9DjVwOAWN0fUKShwZyZHnyLU= | 115 | github.com/bnema/zerowrap v1.4.1 h1:v70w8LDU2+FU+EX/etY9DjVwOAWN0fUKShwZyZHnyLU= | ||
M internal/adapters/cilogs/cilogs.go +2 -0
| @@ -244,6 +244,8 @@ func (s *Store) Count(_ context.Context, ref ports.CILogRef) (int64, error) { | |||
| 244 | 244 | } | |
| 245 | 245 | ||
| 246 | 246 | // Read returns lines from line number from. | |
| 247 | + | // | |
| 248 | + | //hexcheck:ignore suspicious-business-logic-in-adapter reads a bounded snapshot of stored log lines using sparse offsets and maps missing or out-of-range reads to port errors | |
| 247 | 249 | func (s *Store) Read(_ context.Context, ref ports.CILogRef, from int64, maxLines, maxBytes int) ([]domain.CILogLine, error) { | |
| 248 | 250 | if !validRef(ref) || from < 0 { | |
| 249 | 251 | return nil, domain.ErrNotFound | |
| @@ -244,6 +244,8 @@ func (s *Store) Count(_ context.Context, ref ports.CILogRef) (int64, error) { | |||||
| 244 | } | 244 | } | ||
| 245 | 245 | ||||
| 246 | // Read returns lines from line number from. | 246 | // Read returns lines from line number from. | ||
| 247 | + | // | |||
| 248 | + | //hexcheck:ignore suspicious-business-logic-in-adapter reads a bounded snapshot of stored log lines using sparse offsets and maps missing or out-of-range reads to port errors | |||
| 247 | func (s *Store) Read(_ context.Context, ref ports.CILogRef, from int64, maxLines, maxBytes int) ([]domain.CILogLine, error) { | 249 | func (s *Store) Read(_ context.Context, ref ports.CILogRef, from int64, maxLines, maxBytes int) ([]domain.CILogLine, error) { | ||
| 248 | if !validRef(ref) || from < 0 { | 250 | if !validRef(ref) || from < 0 { | ||
| 249 | return nil, domain.ErrNotFound | 251 | return nil, domain.ErrNotFound | ||
M internal/adapters/cisummaries/cisummaries.go +2 -0
| @@ -56,6 +56,8 @@ func (s *Store) path(ref ports.CILogRef, step int32) string { | |||
| 56 | 56 | } | |
| 57 | 57 | ||
| 58 | 58 | // Put stores the summary of a step, or removes it when markdown is empty. | |
| 59 | + | // | |
| 60 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates storage coordinates and atomically writes a step summary, deleting its file when empty | |
| 59 | 61 | func (s *Store) Put(_ context.Context, ref ports.CILogRef, step int32, markdown string) error { | |
| 60 | 62 | if !validRef(ref) || step < 1 || step > domain.CIMaxSteps { | |
| 61 | 63 | return domain.ErrNotFound | |
| @@ -56,6 +56,8 @@ func (s *Store) path(ref ports.CILogRef, step int32) string { | |||||
| 56 | } | 56 | } | ||
| 57 | 57 | ||||
| 58 | // Put stores the summary of a step, or removes it when markdown is empty. | 58 | // Put stores the summary of a step, or removes it when markdown is empty. | ||
| 59 | + | // | |||
| 60 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates storage coordinates and atomically writes a step summary, deleting its file when empty | |||
| 59 | func (s *Store) Put(_ context.Context, ref ports.CILogRef, step int32, markdown string) error { | 61 | func (s *Store) Put(_ context.Context, ref ports.CILogRef, step int32, markdown string) error { | ||
| 60 | if !validRef(ref) || step < 1 || step > domain.CIMaxSteps { | 62 | if !validRef(ref) || step < 1 || step > domain.CIMaxSteps { | ||
| 61 | return domain.ErrNotFound | 63 | return domain.ErrNotFound | ||
M internal/adapters/ermitegit/commitobjects.go +1 -1
| @@ -22,7 +22,7 @@ var _ ports.CommitObjectReader = (*Adapter)(nil) | |||
| 22 | 22 | // always serves it, and the wrapped reader only the repositories the library | |
| 23 | 23 | // cannot read. | |
| 24 | 24 | // | |
| 25 | - | //hexcheck:ignore suspicious-business-logic-in-adapter applies the limits of the port and of the domain | |
| 25 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for commit eligibility and byte budgets; pending move to domain/usecase | |
| 26 | 26 | func (a *Adapter) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | |
| 27 | 27 | if len(ids) > ports.MaxCommitLimit { | |
| 28 | 28 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | |
| @@ -22,7 +22,7 @@ var _ ports.CommitObjectReader = (*Adapter)(nil) | |||||
| 22 | // always serves it, and the wrapped reader only the repositories the library | 22 | // always serves it, and the wrapped reader only the repositories the library | ||
| 23 | // cannot read. | 23 | // cannot read. | ||
| 24 | // | 24 | // | ||
| 25 | - | //hexcheck:ignore suspicious-business-logic-in-adapter applies the limits of the port and of the domain | 25 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for commit eligibility and byte budgets; pending move to domain/usecase |
| 26 | func (a *Adapter) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | 26 | func (a *Adapter) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | ||
| 27 | if len(ids) > ports.MaxCommitLimit { | 27 | if len(ids) > ports.MaxCommitLimit { | ||
| 28 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | 28 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | ||
M internal/adapters/ermitegit/convert.go +1 -5
| @@ -27,8 +27,6 @@ func domainID(id git.ObjectID) (domain.ObjectID, error) { return domain.ParseObj | |||
| 27 | 27 | // listRefs lists HEAD, then the branches, then the tags, like gitcli: a tag | |
| 28 | 28 | // follows to its commit when it leads to one; HEAD takes the ids of its | |
| 29 | 29 | // branch or tag, and only the name of an unborn branch. | |
| 30 | - | // | |
| 31 | - | //hexcheck:ignore suspicious-business-logic-in-adapter converts ermite-git values into domain values; the limits and the orders come from domain | |
| 32 | 30 | func listRefs(r *git.Repo) ([]domain.Ref, error) { | |
| 33 | 31 | var refs []domain.Ref | |
| 34 | 32 | byName := make(map[string]domain.Ref) | |
| @@ -127,7 +125,7 @@ func peelID(r *git.Repo, id git.ObjectID) (_ git.ObjectID, ok bool, _ error) { | |||
| 127 | 125 | // abbreviated id as written. It does not use Repo.Resolve, whose order is | |
| 128 | 126 | // git's own (tags before branches, no ref for a missing full id). | |
| 129 | 127 | // | |
| 130 | - | //hexcheck:ignore suspicious-business-logic-in-adapter tries the candidates of the port in its documented order, like gitcli; the rule is the port contract | |
| 128 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up | |
| 131 | 129 | func resolveRevision(r *git.Repo, rev domain.Revision) (resolved, error) { | |
| 132 | 130 | s := rev.String() | |
| 133 | 131 | if rev.IsHead() || s == "HEAD" { | |
| @@ -477,8 +475,6 @@ func fillLastCommits(ctx context.Context, r *git.Repo, commit domain.ObjectID, d | |||
| 477 | 475 | // The ids, the names, the emails and the message share one backing string, cut | |
| 478 | 476 | // into substrings: one allocation for the text of a commit instead of one per | |
| 479 | 477 | // field. | |
| 480 | - | // | |
| 481 | - | //hexcheck:ignore suspicious-business-logic-in-adapter converts ermite-git values into domain values; the limits and the orders come from domain | |
| 482 | 478 | func convertCommit(c *git.Commit) (domain.Commit, error) { | |
| 483 | 479 | if len(c.Encoding) > 0 && !isUTF8Label(c.Encoding) { | |
| 484 | 480 | return domain.Commit{}, errFallback | |
| @@ -27,8 +27,6 @@ func domainID(id git.ObjectID) (domain.ObjectID, error) { return domain.ParseObj | |||||
| 27 | // listRefs lists HEAD, then the branches, then the tags, like gitcli: a tag | 27 | // listRefs lists HEAD, then the branches, then the tags, like gitcli: a tag | ||
| 28 | // follows to its commit when it leads to one; HEAD takes the ids of its | 28 | // follows to its commit when it leads to one; HEAD takes the ids of its | ||
| 29 | // branch or tag, and only the name of an unborn branch. | 29 | // branch or tag, and only the name of an unborn branch. | ||
| 30 | - | // | |||
| 31 | - | //hexcheck:ignore suspicious-business-logic-in-adapter converts ermite-git values into domain values; the limits and the orders come from domain | |||
| 32 | func listRefs(r *git.Repo) ([]domain.Ref, error) { | 30 | func listRefs(r *git.Repo) ([]domain.Ref, error) { | ||
| 33 | var refs []domain.Ref | 31 | var refs []domain.Ref | ||
| 34 | byName := make(map[string]domain.Ref) | 32 | byName := make(map[string]domain.Ref) | ||
| @@ -127,7 +125,7 @@ func peelID(r *git.Repo, id git.ObjectID) (_ git.ObjectID, ok bool, _ error) { | |||||
| 127 | // abbreviated id as written. It does not use Repo.Resolve, whose order is | 125 | // abbreviated id as written. It does not use Repo.Resolve, whose order is | ||
| 128 | // git's own (tags before branches, no ref for a missing full id). | 126 | // git's own (tags before branches, no ref for a missing full id). | ||
| 129 | // | 127 | // | ||
| 130 | - | //hexcheck:ignore suspicious-business-logic-in-adapter tries the candidates of the port in its documented order, like gitcli; the rule is the port contract | 128 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up |
| 131 | func resolveRevision(r *git.Repo, rev domain.Revision) (resolved, error) { | 129 | func resolveRevision(r *git.Repo, rev domain.Revision) (resolved, error) { | ||
| 132 | s := rev.String() | 130 | s := rev.String() | ||
| 133 | if rev.IsHead() || s == "HEAD" { | 131 | if rev.IsHead() || s == "HEAD" { | ||
| @@ -477,8 +475,6 @@ func fillLastCommits(ctx context.Context, r *git.Repo, commit domain.ObjectID, d | |||||
| 477 | // The ids, the names, the emails and the message share one backing string, cut | 475 | // The ids, the names, the emails and the message share one backing string, cut | ||
| 478 | // into substrings: one allocation for the text of a commit instead of one per | 476 | // into substrings: one allocation for the text of a commit instead of one per | ||
| 479 | // field. | 477 | // field. | ||
| 480 | - | // | |||
| 481 | - | //hexcheck:ignore suspicious-business-logic-in-adapter converts ermite-git values into domain values; the limits and the orders come from domain | |||
| 482 | func convertCommit(c *git.Commit) (domain.Commit, error) { | 478 | func convertCommit(c *git.Commit) (domain.Commit, error) { | ||
| 483 | if len(c.Encoding) > 0 && !isUTF8Label(c.Encoding) { | 479 | if len(c.Encoding) > 0 && !isUTF8Label(c.Encoding) { | ||
| 484 | return domain.Commit{}, errFallback | 480 | return domain.Commit{}, errFallback | ||
M internal/adapters/gitcli/archive.go +0 -2
| @@ -28,8 +28,6 @@ var _ ports.GitArchive = (*Git)(nil) | |||
| 28 | 28 | // not by a gzip binary. A client that goes away ends ctx, which kills git. | |
| 29 | 29 | // Nothing is written to w when the commit does not exist | |
| 30 | 30 | // (domain.ErrNotFound). | |
| 31 | - | // | |
| 32 | - | //hexcheck:ignore suspicious-business-logic-in-adapter runs git archive and compresses its output: a process concern, access and naming are the use case's | |
| 33 | 31 | func (g *Git) Archive(ctx context.Context, repo domain.RepoName, commit domain.ObjectID, prefix string, w io.Writer) error { | |
| 34 | 32 | dir, err := g.repoDir(repo) | |
| 35 | 33 | if err != nil { | |
| @@ -28,8 +28,6 @@ var _ ports.GitArchive = (*Git)(nil) | |||||
| 28 | // not by a gzip binary. A client that goes away ends ctx, which kills git. | 28 | // not by a gzip binary. A client that goes away ends ctx, which kills git. | ||
| 29 | // Nothing is written to w when the commit does not exist | 29 | // Nothing is written to w when the commit does not exist | ||
| 30 | // (domain.ErrNotFound). | 30 | // (domain.ErrNotFound). | ||
| 31 | - | // | |||
| 32 | - | //hexcheck:ignore suspicious-business-logic-in-adapter runs git archive and compresses its output: a process concern, access and naming are the use case's | |||
| 33 | func (g *Git) Archive(ctx context.Context, repo domain.RepoName, commit domain.ObjectID, prefix string, w io.Writer) error { | 31 | func (g *Git) Archive(ctx context.Context, repo domain.RepoName, commit domain.ObjectID, prefix string, w io.Writer) error { | ||
| 34 | dir, err := g.repoDir(repo) | 32 | dir, err := g.repoDir(repo) | ||
| 35 | if err != nil { | 33 | if err != nil { | ||
M internal/adapters/gitcli/changed.go +0 -4
| @@ -21,8 +21,6 @@ const emptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" | |||
| 21 | 21 | // renames not detected (a rename lists both paths, as GitHub's push filters | |
| 22 | 22 | // see it), and stops reading after max paths: truncated tells there were more. | |
| 23 | 23 | // A zero base diffs against the empty tree. | |
| 24 | - | // | |
| 25 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the path list git prints; the bound comes from the port | |
| 26 | 24 | func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limit int) ([]string, bool, error) { | |
| 27 | 25 | if limit < 1 || head.IsZero() { | |
| 28 | 26 | return nil, false, fmt.Errorf("changed paths: %w: limit %d", domain.ErrInvalid, limit) | |
| @@ -63,8 +61,6 @@ func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head | |||
| 63 | 61 | // (refs/heads/*), newest first, at most limit. It runs | |
| 64 | 62 | // `git log --not --branches --not <head>`: tags do not count, so the commit of | |
| 65 | 63 | // another tag that no branch has is listed. | |
| 66 | - | // | |
| 67 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |
| 68 | 64 | func (g *Git) CommitsOffBranches(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | |
| 69 | 65 | if head.IsZero() { | |
| 70 | 66 | return nil, false, fmt.Errorf("commits off branches: %w: no head", domain.ErrInvalid) | |
| @@ -21,8 +21,6 @@ const emptyTree = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" | |||||
| 21 | // renames not detected (a rename lists both paths, as GitHub's push filters | 21 | // renames not detected (a rename lists both paths, as GitHub's push filters | ||
| 22 | // see it), and stops reading after max paths: truncated tells there were more. | 22 | // see it), and stops reading after max paths: truncated tells there were more. | ||
| 23 | // A zero base diffs against the empty tree. | 23 | // A zero base diffs against the empty tree. | ||
| 24 | - | // | |||
| 25 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the path list git prints; the bound comes from the port | |||
| 26 | func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limit int) ([]string, bool, error) { | 24 | func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limit int) ([]string, bool, error) { | ||
| 27 | if limit < 1 || head.IsZero() { | 25 | if limit < 1 || head.IsZero() { | ||
| 28 | return nil, false, fmt.Errorf("changed paths: %w: limit %d", domain.ErrInvalid, limit) | 26 | return nil, false, fmt.Errorf("changed paths: %w: limit %d", domain.ErrInvalid, limit) | ||
| @@ -63,8 +61,6 @@ func (g *Git) ChangedPaths(ctx context.Context, repo domain.RepoName, base, head | |||||
| 63 | // (refs/heads/*), newest first, at most limit. It runs | 61 | // (refs/heads/*), newest first, at most limit. It runs | ||
| 64 | // `git log --not --branches --not <head>`: tags do not count, so the commit of | 62 | // `git log --not --branches --not <head>`: tags do not count, so the commit of | ||
| 65 | // another tag that no branch has is listed. | 63 | // another tag that no branch has is listed. | ||
| 66 | - | // | |||
| 67 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |||
| 68 | func (g *Git) CommitsOffBranches(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | 64 | func (g *Git) CommitsOffBranches(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | ||
| 69 | if head.IsZero() { | 65 | if head.IsZero() { | ||
| 70 | return nil, false, fmt.Errorf("commits off branches: %w: no head", domain.ErrInvalid) | 66 | return nil, false, fmt.Errorf("commits off branches: %w: no head", domain.ErrInvalid) | ||
M internal/adapters/gitcli/commitobjects.go +1 -1
| @@ -19,7 +19,7 @@ var _ ports.CommitObjectReader = (*Git)(nil) | |||
| 19 | 19 | // that would take the total over domain.MaxCommitObjectsBytes (known from | |
| 20 | 20 | // `info`, before any content is read, so the stream stays consistent). | |
| 21 | 21 | // | |
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter applies the limits of the port and of the domain | |
| 22 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for commit eligibility and byte budgets; pending move to domain/usecase | |
| 23 | 23 | func (g *Git) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | |
| 24 | 24 | if len(ids) > ports.MaxCommitLimit { | |
| 25 | 25 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | |
| @@ -19,7 +19,7 @@ var _ ports.CommitObjectReader = (*Git)(nil) | |||||
| 19 | // that would take the total over domain.MaxCommitObjectsBytes (known from | 19 | // that would take the total over domain.MaxCommitObjectsBytes (known from | ||
| 20 | // `info`, before any content is read, so the stream stays consistent). | 20 | // `info`, before any content is read, so the stream stays consistent). | ||
| 21 | // | 21 | // | ||
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter applies the limits of the port and of the domain | 22 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for commit eligibility and byte budgets; pending move to domain/usecase |
| 23 | func (g *Git) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | 23 | func (g *Git) ReadCommitObjects(ctx context.Context, repo domain.RepoName, ids []domain.ObjectID) (map[domain.ObjectID][]byte, error) { | ||
| 24 | if len(ids) > ports.MaxCommitLimit { | 24 | if len(ids) > ports.MaxCommitLimit { | ||
| 25 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | 25 | return nil, fmt.Errorf("%w: %d commit objects asked, at most %d", domain.ErrInvalid, len(ids), ports.MaxCommitLimit) | ||
M internal/adapters/gitcli/diff.go +1 -13
| @@ -32,8 +32,6 @@ const maxDiffLine = 64 << 10 | |||
| 32 | 32 | // Statistics come from the line counts, binary files from their "-" counts. | |
| 33 | 33 | // The patch is parsed as it streams: nothing beyond the limits is kept, and | |
| 34 | 34 | // git is stopped once nothing more is needed. | |
| 35 | - | // | |
| 36 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git diff-tree output into the domain diff, applying the limits the port passes in | |
| 37 | 35 | func (g *Git) GetCommit(ctx context.Context, repo domain.RepoName, rev domain.Revision, limits domain.DiffLimits) (domain.CommitDetail, error) { | |
| 38 | 36 | dir, err := g.repoDir(repo) | |
| 39 | 37 | if err != nil { | |
| @@ -91,7 +89,7 @@ type rawEntry struct { | |||
| 91 | 89 | ||
| 92 | 90 | // readDiff parses the output of diff-tree --raw --numstat -p. | |
| 93 | 91 | // | |
| 94 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values, applying the limits the port passes in | |
| 92 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for diff windowing and truncation budgets; pending move to domain/usecase | |
| 95 | 93 | func readDiff(r *bufio.Reader, limits domain.DiffLimits) (domain.Diff, domain.DiffStats, error) { | |
| 96 | 94 | entries, err := readRaw(r) | |
| 97 | 95 | if err != nil { | |
| @@ -189,8 +187,6 @@ func wantsHunks(e *rawEntry, limits domain.DiffLimits, linesLeft, bytesLeft int) | |||
| 189 | 187 | } | |
| 190 | 188 | ||
| 191 | 189 | // readRaw reads the `--raw -z` records, which start with ':'. | |
| 192 | - | // | |
| 193 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |
| 194 | 190 | func readRaw(r *bufio.Reader) ([]rawEntry, error) { | |
| 195 | 191 | var entries []rawEntry | |
| 196 | 192 | for { | |
| @@ -241,8 +237,6 @@ func unexpectedEOF(err error) error { | |||
| 241 | 237 | ||
| 242 | 238 | // parseRawMeta parses ":<old mode> <new mode> <old id> <new id> <status>" and | |
| 243 | 239 | // returns the number of paths that follow. | |
| 244 | - | // | |
| 245 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |
| 246 | 240 | func parseRawMeta(meta string) (rawEntry, int, error) { | |
| 247 | 241 | f := strings.Fields(strings.TrimPrefix(meta, ":")) | |
| 248 | 242 | if len(f) != 5 || f[4] == "" { | |
| @@ -296,8 +290,6 @@ func parseRawMeta(meta string) (rawEntry, int, error) { | |||
| 296 | 290 | ||
| 297 | 291 | // readNumstat reads one `--numstat -z` record per entry. A binary file has | |
| 298 | 292 | // "-" counts. | |
| 299 | - | // | |
| 300 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |
| 301 | 293 | func readNumstat(r *bufio.Reader, entries []rawEntry) error { | |
| 302 | 294 | for i := range entries { | |
| 303 | 295 | tok, err := readToken(r) | |
| @@ -434,8 +426,6 @@ func (p *patchReader) file(sections, max int) (hunks []domain.Hunk, lines int, t | |||
| 434 | 426 | ||
| 435 | 427 | // section reads the hunks of the current section up to the next marker, which | |
| 436 | 428 | // stays pending. It gives up (truncated) after more than max lines. | |
| 437 | - | // | |
| 438 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values, applying the limits the port passes in | |
| 439 | 429 | func (p *patchReader) section(max int) (hunks []domain.Hunk, lines int, truncated bool, err error) { | |
| 440 | 430 | var cur *domain.Hunk | |
| 441 | 431 | var oldN, newN int | |
| @@ -499,8 +489,6 @@ func (p *patchReader) section(max int) (hunks []domain.Hunk, lines int, truncate | |||
| 499 | 489 | } | |
| 500 | 490 | ||
| 501 | 491 | // parseHunkHeader parses "@@ -a[,b] +c[,d] @@[ header]". | |
| 502 | - | // | |
| 503 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |
| 504 | 492 | func parseHunkHeader(s string) (domain.Hunk, error) { | |
| 505 | 493 | bad := func() (domain.Hunk, error) { | |
| 506 | 494 | return domain.Hunk{}, fmt.Errorf("git diff-tree: unexpected hunk header %q", truncateText(s)) | |
| @@ -32,8 +32,6 @@ const maxDiffLine = 64 << 10 | |||||
| 32 | // Statistics come from the line counts, binary files from their "-" counts. | 32 | // Statistics come from the line counts, binary files from their "-" counts. | ||
| 33 | // The patch is parsed as it streams: nothing beyond the limits is kept, and | 33 | // The patch is parsed as it streams: nothing beyond the limits is kept, and | ||
| 34 | // git is stopped once nothing more is needed. | 34 | // git is stopped once nothing more is needed. | ||
| 35 | - | // | |||
| 36 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git diff-tree output into the domain diff, applying the limits the port passes in | |||
| 37 | func (g *Git) GetCommit(ctx context.Context, repo domain.RepoName, rev domain.Revision, limits domain.DiffLimits) (domain.CommitDetail, error) { | 35 | func (g *Git) GetCommit(ctx context.Context, repo domain.RepoName, rev domain.Revision, limits domain.DiffLimits) (domain.CommitDetail, error) { | ||
| 38 | dir, err := g.repoDir(repo) | 36 | dir, err := g.repoDir(repo) | ||
| 39 | if err != nil { | 37 | if err != nil { | ||
| @@ -91,7 +89,7 @@ type rawEntry struct { | |||||
| 91 | 89 | ||||
| 92 | // readDiff parses the output of diff-tree --raw --numstat -p. | 90 | // readDiff parses the output of diff-tree --raw --numstat -p. | ||
| 93 | // | 91 | // | ||
| 94 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values, applying the limits the port passes in | 92 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for diff windowing and truncation budgets; pending move to domain/usecase |
| 95 | func readDiff(r *bufio.Reader, limits domain.DiffLimits) (domain.Diff, domain.DiffStats, error) { | 93 | func readDiff(r *bufio.Reader, limits domain.DiffLimits) (domain.Diff, domain.DiffStats, error) { | ||
| 96 | entries, err := readRaw(r) | 94 | entries, err := readRaw(r) | ||
| 97 | if err != nil { | 95 | if err != nil { | ||
| @@ -189,8 +187,6 @@ func wantsHunks(e *rawEntry, limits domain.DiffLimits, linesLeft, bytesLeft int) | |||||
| 189 | } | 187 | } | ||
| 190 | 188 | ||||
| 191 | // readRaw reads the `--raw -z` records, which start with ':'. | 189 | // readRaw reads the `--raw -z` records, which start with ':'. | ||
| 192 | - | // | |||
| 193 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |||
| 194 | func readRaw(r *bufio.Reader) ([]rawEntry, error) { | 190 | func readRaw(r *bufio.Reader) ([]rawEntry, error) { | ||
| 195 | var entries []rawEntry | 191 | var entries []rawEntry | ||
| 196 | for { | 192 | for { | ||
| @@ -241,8 +237,6 @@ func unexpectedEOF(err error) error { | |||||
| 241 | 237 | ||||
| 242 | // parseRawMeta parses ":<old mode> <new mode> <old id> <new id> <status>" and | 238 | // parseRawMeta parses ":<old mode> <new mode> <old id> <new id> <status>" and | ||
| 243 | // returns the number of paths that follow. | 239 | // returns the number of paths that follow. | ||
| 244 | - | // | |||
| 245 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |||
| 246 | func parseRawMeta(meta string) (rawEntry, int, error) { | 240 | func parseRawMeta(meta string) (rawEntry, int, error) { | ||
| 247 | f := strings.Fields(strings.TrimPrefix(meta, ":")) | 241 | f := strings.Fields(strings.TrimPrefix(meta, ":")) | ||
| 248 | if len(f) != 5 || f[4] == "" { | 242 | if len(f) != 5 || f[4] == "" { | ||
| @@ -296,8 +290,6 @@ func parseRawMeta(meta string) (rawEntry, int, error) { | |||||
| 296 | 290 | ||||
| 297 | // readNumstat reads one `--numstat -z` record per entry. A binary file has | 291 | // readNumstat reads one `--numstat -z` record per entry. A binary file has | ||
| 298 | // "-" counts. | 292 | // "-" counts. | ||
| 299 | - | // | |||
| 300 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |||
| 301 | func readNumstat(r *bufio.Reader, entries []rawEntry) error { | 293 | func readNumstat(r *bufio.Reader, entries []rawEntry) error { | ||
| 302 | for i := range entries { | 294 | for i := range entries { | ||
| 303 | tok, err := readToken(r) | 295 | tok, err := readToken(r) | ||
| @@ -434,8 +426,6 @@ func (p *patchReader) file(sections, max int) (hunks []domain.Hunk, lines int, t | |||||
| 434 | 426 | ||||
| 435 | // section reads the hunks of the current section up to the next marker, which | 427 | // section reads the hunks of the current section up to the next marker, which | ||
| 436 | // stays pending. It gives up (truncated) after more than max lines. | 428 | // stays pending. It gives up (truncated) after more than max lines. | ||
| 437 | - | // | |||
| 438 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values, applying the limits the port passes in | |||
| 439 | func (p *patchReader) section(max int) (hunks []domain.Hunk, lines int, truncated bool, err error) { | 429 | func (p *patchReader) section(max int) (hunks []domain.Hunk, lines int, truncated bool, err error) { | ||
| 440 | var cur *domain.Hunk | 430 | var cur *domain.Hunk | ||
| 441 | var oldN, newN int | 431 | var oldN, newN int | ||
| @@ -499,8 +489,6 @@ func (p *patchReader) section(max int) (hunks []domain.Hunk, lines int, truncate | |||||
| 499 | } | 489 | } | ||
| 500 | 490 | ||||
| 501 | // parseHunkHeader parses "@@ -a[,b] +c[,d] @@[ header]". | 491 | // parseHunkHeader parses "@@ -a[,b] +c[,d] @@[ header]". | ||
| 502 | - | // | |||
| 503 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values | |||
| 504 | func parseHunkHeader(s string) (domain.Hunk, error) { | 492 | func parseHunkHeader(s string) (domain.Hunk, error) { | ||
| 505 | bad := func() (domain.Hunk, error) { | 493 | bad := func() (domain.Hunk, error) { | ||
| 506 | return domain.Hunk{}, fmt.Errorf("git diff-tree: unexpected hunk header %q", truncateText(s)) | 494 | return domain.Hunk{}, fmt.Errorf("git diff-tree: unexpected hunk header %q", truncateText(s)) | ||
M internal/adapters/gitcli/merge.go +0 -16
| @@ -39,8 +39,6 @@ func parseID(out string) (domain.ObjectID, error) { | |||
| 39 | 39 | } | |
| 40 | 40 | ||
| 41 | 41 | // BranchHead resolves refs/heads/<branch>^{commit} with `cat-file`. | |
| 42 | - | // | |
| 43 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a branch name to a git object name | |
| 44 | 42 | func (g *Git) BranchHead(ctx context.Context, repo domain.RepoName, branch string) (domain.ObjectID, error) { | |
| 45 | 43 | dir, err := g.repoDir(repo) | |
| 46 | 44 | if err != nil { | |
| @@ -95,8 +93,6 @@ func (g *Git) HasCommit(ctx context.Context, repo domain.RepoName, id domain.Obj | |||
| 95 | 93 | } | |
| 96 | 94 | ||
| 97 | 95 | // MergeBase runs `git merge-base`, which exits 1 when there is none. | |
| 98 | - | // | |
| 99 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps git exit codes to the domain not found error | |
| 100 | 96 | func (g *Git) MergeBase(ctx context.Context, repo domain.RepoName, a, b domain.ObjectID) (domain.ObjectID, error) { | |
| 101 | 97 | dir, err := g.repoDir(repo) | |
| 102 | 98 | if err != nil { | |
| @@ -129,8 +125,6 @@ func (g *Git) IsAncestor(ctx context.Context, repo domain.RepoName, ancestor, de | |||
| 129 | 125 | } | |
| 130 | 126 | ||
| 131 | 127 | // ListRange runs `git log <head> ^<exclude>`. | |
| 132 | - | // | |
| 133 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |
| 134 | 128 | func (g *Git) ListRange(ctx context.Context, repo domain.RepoName, exclude, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | |
| 135 | 129 | var excluded []string | |
| 136 | 130 | if !exclude.IsZero() { | |
| @@ -142,8 +136,6 @@ func (g *Git) ListRange(ctx context.Context, repo domain.RepoName, exclude, head | |||
| 142 | 136 | // logCommits runs `git log` for the commits reachable from head: revArgs go | |
| 143 | 137 | // before the head (options such as --not), excluded after it. Newest first, | |
| 144 | 138 | // at most limit; more says there were others. | |
| 145 | - | // | |
| 146 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |
| 147 | 139 | func (g *Git) logCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int, revArgs, excluded []string) ([]domain.Commit, bool, error) { | |
| 148 | 140 | if limit < 1 || limit > ports.MaxCommitLimit { | |
| 149 | 141 | return nil, false, fmt.Errorf("list range: %w: limit %d", domain.ErrInvalidPageSize, limit) | |
| @@ -183,8 +175,6 @@ func (g *Git) logCommits(ctx context.Context, repo domain.RepoName, head domain. | |||
| 183 | 175 | } | |
| 184 | 176 | ||
| 185 | 177 | // DiffCommits reads the diff between two commits like GetCommit does. | |
| 186 | - | // | |
| 187 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads a git diff into the domain diff with the limits the port passes in | |
| 188 | 178 | func (g *Git) DiffCommits(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limits domain.DiffLimits) (domain.DiffStats, domain.Diff, error) { | |
| 189 | 179 | dir, err := g.repoDir(repo) | |
| 190 | 180 | if err != nil { | |
| @@ -198,8 +188,6 @@ func (g *Git) DiffCommits(ctx context.Context, repo domain.RepoName, base, head | |||
| 198 | 188 | } | |
| 199 | 189 | ||
| 200 | 190 | // CommitTree runs `git rev-parse <commit>^{tree}`. | |
| 201 | - | // | |
| 202 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses the id git printed | |
| 203 | 191 | func (g *Git) CommitTree(ctx context.Context, repo domain.RepoName, id domain.ObjectID) (domain.ObjectID, error) { | |
| 204 | 192 | dir, err := g.repoDir(repo) | |
| 205 | 193 | if err != nil { | |
| @@ -229,8 +217,6 @@ func (g *Git) WriteCommit(ctx context.Context, repo domain.RepoName, object []by | |||
| 229 | 217 | // UpdateBranch runs `git update-ref refs/heads/<branch> <new> <old>`, which | |
| 230 | 218 | // takes the ref lock and refuses when the ref is not at old. A failure is | |
| 231 | 219 | // told from a moved branch by reading the branch again. | |
| 232 | - | // | |
| 233 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a refused update-ref to the conflict error of the port | |
| 234 | 220 | func (g *Git) UpdateBranch(ctx context.Context, repo domain.RepoName, branch string, old, newID domain.ObjectID) error { | |
| 235 | 221 | dir, err := g.repoDir(repo) | |
| 236 | 222 | if err != nil { | |
| @@ -252,8 +238,6 @@ func (g *Git) UpdateBranch(ctx context.Context, repo domain.RepoName, branch str | |||
| 252 | 238 | // DeleteBranch runs `git update-ref -d refs/heads/<branch> <old>`, which takes | |
| 253 | 239 | // the ref lock and refuses when the ref is not at old. A failure is told from | |
| 254 | 240 | // a moved or deleted branch by reading the branch again. | |
| 255 | - | // | |
| 256 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a refused update-ref to the conflict error of the port | |
| 257 | 241 | func (g *Git) DeleteBranch(ctx context.Context, repo domain.RepoName, branch string, old domain.ObjectID) error { | |
| 258 | 242 | dir, err := g.repoDir(repo) | |
| 259 | 243 | if err != nil { | |
| @@ -39,8 +39,6 @@ func parseID(out string) (domain.ObjectID, error) { | |||||
| 39 | } | 39 | } | ||
| 40 | 40 | ||||
| 41 | // BranchHead resolves refs/heads/<branch>^{commit} with `cat-file`. | 41 | // BranchHead resolves refs/heads/<branch>^{commit} with `cat-file`. | ||
| 42 | - | // | |||
| 43 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a branch name to a git object name | |||
| 44 | func (g *Git) BranchHead(ctx context.Context, repo domain.RepoName, branch string) (domain.ObjectID, error) { | 42 | func (g *Git) BranchHead(ctx context.Context, repo domain.RepoName, branch string) (domain.ObjectID, error) { | ||
| 45 | dir, err := g.repoDir(repo) | 43 | dir, err := g.repoDir(repo) | ||
| 46 | if err != nil { | 44 | if err != nil { | ||
| @@ -95,8 +93,6 @@ func (g *Git) HasCommit(ctx context.Context, repo domain.RepoName, id domain.Obj | |||||
| 95 | } | 93 | } | ||
| 96 | 94 | ||||
| 97 | // MergeBase runs `git merge-base`, which exits 1 when there is none. | 95 | // MergeBase runs `git merge-base`, which exits 1 when there is none. | ||
| 98 | - | // | |||
| 99 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps git exit codes to the domain not found error | |||
| 100 | func (g *Git) MergeBase(ctx context.Context, repo domain.RepoName, a, b domain.ObjectID) (domain.ObjectID, error) { | 96 | func (g *Git) MergeBase(ctx context.Context, repo domain.RepoName, a, b domain.ObjectID) (domain.ObjectID, error) { | ||
| 101 | dir, err := g.repoDir(repo) | 97 | dir, err := g.repoDir(repo) | ||
| 102 | if err != nil { | 98 | if err != nil { | ||
| @@ -129,8 +125,6 @@ func (g *Git) IsAncestor(ctx context.Context, repo domain.RepoName, ancestor, de | |||||
| 129 | } | 125 | } | ||
| 130 | 126 | ||||
| 131 | // ListRange runs `git log <head> ^<exclude>`. | 127 | // ListRange runs `git log <head> ^<exclude>`. | ||
| 132 | - | // | |||
| 133 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |||
| 134 | func (g *Git) ListRange(ctx context.Context, repo domain.RepoName, exclude, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | 128 | func (g *Git) ListRange(ctx context.Context, repo domain.RepoName, exclude, head domain.ObjectID, limit int) ([]domain.Commit, bool, error) { | ||
| 135 | var excluded []string | 129 | var excluded []string | ||
| 136 | if !exclude.IsZero() { | 130 | if !exclude.IsZero() { | ||
| @@ -142,8 +136,6 @@ func (g *Git) ListRange(ctx context.Context, repo domain.RepoName, exclude, head | |||||
| 142 | // logCommits runs `git log` for the commits reachable from head: revArgs go | 136 | // logCommits runs `git log` for the commits reachable from head: revArgs go | ||
| 143 | // before the head (options such as --not), excluded after it. Newest first, | 137 | // before the head (options such as --not), excluded after it. Newest first, | ||
| 144 | // at most limit; more says there were others. | 138 | // at most limit; more says there were others. | ||
| 145 | - | // | |||
| 146 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; the limit comes from the port | |||
| 147 | func (g *Git) logCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int, revArgs, excluded []string) ([]domain.Commit, bool, error) { | 139 | func (g *Git) logCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID, limit int, revArgs, excluded []string) ([]domain.Commit, bool, error) { | ||
| 148 | if limit < 1 || limit > ports.MaxCommitLimit { | 140 | if limit < 1 || limit > ports.MaxCommitLimit { | ||
| 149 | return nil, false, fmt.Errorf("list range: %w: limit %d", domain.ErrInvalidPageSize, limit) | 141 | return nil, false, fmt.Errorf("list range: %w: limit %d", domain.ErrInvalidPageSize, limit) | ||
| @@ -183,8 +175,6 @@ func (g *Git) logCommits(ctx context.Context, repo domain.RepoName, head domain. | |||||
| 183 | } | 175 | } | ||
| 184 | 176 | ||||
| 185 | // DiffCommits reads the diff between two commits like GetCommit does. | 177 | // DiffCommits reads the diff between two commits like GetCommit does. | ||
| 186 | - | // | |||
| 187 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads a git diff into the domain diff with the limits the port passes in | |||
| 188 | func (g *Git) DiffCommits(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limits domain.DiffLimits) (domain.DiffStats, domain.Diff, error) { | 178 | func (g *Git) DiffCommits(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID, limits domain.DiffLimits) (domain.DiffStats, domain.Diff, error) { | ||
| 189 | dir, err := g.repoDir(repo) | 179 | dir, err := g.repoDir(repo) | ||
| 190 | if err != nil { | 180 | if err != nil { | ||
| @@ -198,8 +188,6 @@ func (g *Git) DiffCommits(ctx context.Context, repo domain.RepoName, base, head | |||||
| 198 | } | 188 | } | ||
| 199 | 189 | ||||
| 200 | // CommitTree runs `git rev-parse <commit>^{tree}`. | 190 | // CommitTree runs `git rev-parse <commit>^{tree}`. | ||
| 201 | - | // | |||
| 202 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses the id git printed | |||
| 203 | func (g *Git) CommitTree(ctx context.Context, repo domain.RepoName, id domain.ObjectID) (domain.ObjectID, error) { | 191 | func (g *Git) CommitTree(ctx context.Context, repo domain.RepoName, id domain.ObjectID) (domain.ObjectID, error) { | ||
| 204 | dir, err := g.repoDir(repo) | 192 | dir, err := g.repoDir(repo) | ||
| 205 | if err != nil { | 193 | if err != nil { | ||
| @@ -229,8 +217,6 @@ func (g *Git) WriteCommit(ctx context.Context, repo domain.RepoName, object []by | |||||
| 229 | // UpdateBranch runs `git update-ref refs/heads/<branch> <new> <old>`, which | 217 | // UpdateBranch runs `git update-ref refs/heads/<branch> <new> <old>`, which | ||
| 230 | // takes the ref lock and refuses when the ref is not at old. A failure is | 218 | // takes the ref lock and refuses when the ref is not at old. A failure is | ||
| 231 | // told from a moved branch by reading the branch again. | 219 | // told from a moved branch by reading the branch again. | ||
| 232 | - | // | |||
| 233 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a refused update-ref to the conflict error of the port | |||
| 234 | func (g *Git) UpdateBranch(ctx context.Context, repo domain.RepoName, branch string, old, newID domain.ObjectID) error { | 220 | func (g *Git) UpdateBranch(ctx context.Context, repo domain.RepoName, branch string, old, newID domain.ObjectID) error { | ||
| 235 | dir, err := g.repoDir(repo) | 221 | dir, err := g.repoDir(repo) | ||
| 236 | if err != nil { | 222 | if err != nil { | ||
| @@ -252,8 +238,6 @@ func (g *Git) UpdateBranch(ctx context.Context, repo domain.RepoName, branch str | |||||
| 252 | // DeleteBranch runs `git update-ref -d refs/heads/<branch> <old>`, which takes | 238 | // DeleteBranch runs `git update-ref -d refs/heads/<branch> <old>`, which takes | ||
| 253 | // the ref lock and refuses when the ref is not at old. A failure is told from | 239 | // the ref lock and refuses when the ref is not at old. A failure is told from | ||
| 254 | // a moved or deleted branch by reading the branch again. | 240 | // a moved or deleted branch by reading the branch again. | ||
| 255 | - | // | |||
| 256 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a refused update-ref to the conflict error of the port | |||
| 257 | func (g *Git) DeleteBranch(ctx context.Context, repo domain.RepoName, branch string, old domain.ObjectID) error { | 241 | func (g *Git) DeleteBranch(ctx context.Context, repo domain.RepoName, branch string, old domain.ObjectID) error { | ||
| 258 | dir, err := g.repoDir(repo) | 242 | dir, err := g.repoDir(repo) | ||
| 259 | if err != nil { | 243 | if err != nil { | ||
M internal/adapters/gitcli/pull.go +0 -2
| @@ -18,8 +18,6 @@ var _ ports.PullGit = (*Git)(nil) | |||
| 18 | 18 | // database and touches no ref or index: it prints the tree of the result and | |
| 19 | 19 | // exits 0, or exits 1 when the merge conflicts. Commits with no common history | |
| 20 | 20 | // do not merge (GitHub makes no test merge for them either). | |
| 21 | - | // | |
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps git exit codes to the clean/conflict answer of the port | |
| 23 | 21 | func (g *Git) TestMerge(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID) (domain.ObjectID, bool, error) { | |
| 24 | 22 | dir, err := g.repoDir(repo) | |
| 25 | 23 | if err != nil { | |
| @@ -18,8 +18,6 @@ var _ ports.PullGit = (*Git)(nil) | |||||
| 18 | // database and touches no ref or index: it prints the tree of the result and | 18 | // database and touches no ref or index: it prints the tree of the result and | ||
| 19 | // exits 0, or exits 1 when the merge conflicts. Commits with no common history | 19 | // exits 0, or exits 1 when the merge conflicts. Commits with no common history | ||
| 20 | // do not merge (GitHub makes no test merge for them either). | 20 | // do not merge (GitHub makes no test merge for them either). | ||
| 21 | - | // | |||
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps git exit codes to the clean/conflict answer of the port | |||
| 23 | func (g *Git) TestMerge(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID) (domain.ObjectID, bool, error) { | 21 | func (g *Git) TestMerge(ctx context.Context, repo domain.RepoName, base, head domain.ObjectID) (domain.ObjectID, bool, error) { | ||
| 24 | dir, err := g.repoDir(repo) | 22 | dir, err := g.repoDir(repo) | ||
| 25 | if err != nil { | 23 | if err != nil { | ||
M internal/adapters/gitcli/read.go +5 -13
| @@ -35,8 +35,6 @@ func notFound(err error) bool { return errors.Is(err, errObjectMissing) } | |||
| 35 | 35 | // ListRefs lists HEAD, the branches and the tags with `git for-each-ref`. | |
| 36 | 36 | // An annotated tag is followed to its commit; a tag of a tag is followed with | |
| 37 | 37 | // one `cat-file` request each. | |
| 38 | - | // | |
| 39 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain refs | |
| 40 | 38 | func (g *Git) ListRefs(ctx context.Context, repo domain.RepoName) ([]domain.Ref, error) { | |
| 41 | 39 | dir, err := g.repoDir(repo) | |
| 42 | 40 | if err != nil { | |
| @@ -167,6 +165,8 @@ type revCandidate struct { | |||
| 167 | 165 | // object exists. Otherwise it is the branch, then the tag, then (for "HEAD", | |
| 168 | 166 | // full ref names and abbreviations) as written. Other forms Git understands, | |
| 169 | 167 | // such as "main~2" or "FETCH_HEAD", are not revisions of ermite. | |
| 168 | + | // | |
| 169 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up | |
| 170 | 170 | func candidates(rev domain.Revision) []revCandidate { | |
| 171 | 171 | s := rev.String() | |
| 172 | 172 | switch { | |
| @@ -190,7 +190,7 @@ func candidates(rev domain.Revision) []revCandidate { | |||
| 190 | 190 | ||
| 191 | 191 | // resolve resolves rev on an open cat-file connection. | |
| 192 | 192 | // | |
| 193 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a revision to git object names, a git detail of the reader | |
| 193 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up | |
| 194 | 194 | func resolve(c *catConn, rev domain.Revision) (domain.ResolvedRevision, error) { | |
| 195 | 195 | for _, cand := range candidates(rev) { | |
| 196 | 196 | h, err := c.info(cand.spec) | |
| @@ -213,8 +213,6 @@ func resolve(c *catConn, rev domain.Revision) (domain.ResolvedRevision, error) { | |||
| 213 | 213 | } | |
| 214 | 214 | ||
| 215 | 215 | // ResolveRevision resolves a revision with `cat-file`. | |
| 216 | - | // | |
| 217 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |
| 218 | 216 | func (g *Git) ResolveRevision(ctx context.Context, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | |
| 219 | 217 | dir, err := g.repoDir(repo) | |
| 220 | 218 | if err != nil { | |
| @@ -235,8 +233,6 @@ func (g *Git) ResolveRevision(ctx context.Context, repo domain.RepoName, rev dom | |||
| 235 | 233 | // tag, full ref name, HEAD; a single segment may also be a commit id), longest | |
| 236 | 234 | // first, with up to one `cat-file` request per candidate on the repository's | |
| 237 | 235 | // process. At most domain.MaxRefPathTries segments are tried. | |
| 238 | - | // | |
| 239 | - | //hexcheck:ignore suspicious-business-logic-in-adapter the split is domain.SplitRefPath; this only runs it on a cat-file connection | |
| 240 | 236 | func (g *Git) ResolveRefPath(ctx context.Context, repo domain.RepoName, path string) (domain.RefPath, error) { | |
| 241 | 237 | dir, err := g.repoDir(repo) | |
| 242 | 238 | if err != nil { | |
| @@ -264,6 +260,8 @@ type object struct { | |||
| 264 | 260 | // lookup resolves rev and reads the header of the object at path, in one | |
| 265 | 261 | // request series on the repository's process. A missing path is | |
| 266 | 262 | // domain.ErrNotFound. | |
| 263 | + | // | |
| 264 | + | //hexcheck:ignore suspicious-business-logic-in-adapter uses the business rule for revision resolution order, pending move to domain.Revision in a follow-up, before looking up a path | |
| 267 | 265 | func (g *Git) lookup(ctx context.Context, dir string, rev domain.Revision, path domain.TreePath) (object, error) { | |
| 268 | 266 | var obj object | |
| 269 | 267 | err := g.cat.do(ctx, dir, func(c *catConn) error { | |
| @@ -392,8 +390,6 @@ func (g *Git) GetTree(ctx context.Context, repo domain.RepoName, rev domain.Revi | |||
| 392 | 390 | } | |
| 393 | 391 | ||
| 394 | 392 | // parseTreeEntry parses "<mode> <type> <id> <size>\t<name>" of ls-tree -l. | |
| 395 | - | // | |
| 396 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |
| 397 | 393 | func parseTreeEntry(rec string, parent domain.TreePath) (domain.TreeEntry, error) { | |
| 398 | 394 | meta, name, ok := strings.Cut(rec, "\t") | |
| 399 | 395 | f := strings.Fields(meta) | |
| @@ -487,8 +483,6 @@ feed: | |||
| 487 | 483 | ||
| 488 | 484 | // lastCommit returns the newest commit reachable from head that changed path; | |
| 489 | 485 | // an empty path means head itself. | |
| 490 | - | // | |
| 491 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |
| 492 | 486 | func (g *Git) lastCommit(ctx context.Context, dir string, head domain.ObjectID, path string) (domain.Commit, error) { | |
| 493 | 487 | var c domain.Commit | |
| 494 | 488 | found := false | |
| @@ -520,8 +514,6 @@ const commitFormat = "%H%x00%P%x00%an%x00%ae%x00%at%x00%cn%x00%ce%x00%ct%x00%B" | |||
| 520 | 514 | ||
| 521 | 515 | // readCommit reads one commit in commitFormat. It returns io.EOF at the end | |
| 522 | 516 | // of the output. | |
| 523 | - | // | |
| 524 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |
| 525 | 517 | func readCommit(r *bufio.Reader) (domain.Commit, error) { | |
| 526 | 518 | var f [9]string | |
| 527 | 519 | for i := range f { | |
| @@ -35,8 +35,6 @@ func notFound(err error) bool { return errors.Is(err, errObjectMissing) } | |||||
| 35 | // ListRefs lists HEAD, the branches and the tags with `git for-each-ref`. | 35 | // ListRefs lists HEAD, the branches and the tags with `git for-each-ref`. | ||
| 36 | // An annotated tag is followed to its commit; a tag of a tag is followed with | 36 | // An annotated tag is followed to its commit; a tag of a tag is followed with | ||
| 37 | // one `cat-file` request each. | 37 | // one `cat-file` request each. | ||
| 38 | - | // | |||
| 39 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain refs | |||
| 40 | func (g *Git) ListRefs(ctx context.Context, repo domain.RepoName) ([]domain.Ref, error) { | 38 | func (g *Git) ListRefs(ctx context.Context, repo domain.RepoName) ([]domain.Ref, error) { | ||
| 41 | dir, err := g.repoDir(repo) | 39 | dir, err := g.repoDir(repo) | ||
| 42 | if err != nil { | 40 | if err != nil { | ||
| @@ -167,6 +165,8 @@ type revCandidate struct { | |||||
| 167 | // object exists. Otherwise it is the branch, then the tag, then (for "HEAD", | 165 | // object exists. Otherwise it is the branch, then the tag, then (for "HEAD", | ||
| 168 | // full ref names and abbreviations) as written. Other forms Git understands, | 166 | // full ref names and abbreviations) as written. Other forms Git understands, | ||
| 169 | // such as "main~2" or "FETCH_HEAD", are not revisions of ermite. | 167 | // such as "main~2" or "FETCH_HEAD", are not revisions of ermite. | ||
| 168 | + | // | |||
| 169 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up | |||
| 170 | func candidates(rev domain.Revision) []revCandidate { | 170 | func candidates(rev domain.Revision) []revCandidate { | ||
| 171 | s := rev.String() | 171 | s := rev.String() | ||
| 172 | switch { | 172 | switch { | ||
| @@ -190,7 +190,7 @@ func candidates(rev domain.Revision) []revCandidate { | |||||
| 190 | 190 | ||||
| 191 | // resolve resolves rev on an open cat-file connection. | 191 | // resolve resolves rev on an open cat-file connection. | ||
| 192 | // | 192 | // | ||
| 193 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps a revision to git object names, a git detail of the reader | 193 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for revision resolution order; pending move to domain.Revision in a follow-up |
| 194 | func resolve(c *catConn, rev domain.Revision) (domain.ResolvedRevision, error) { | 194 | func resolve(c *catConn, rev domain.Revision) (domain.ResolvedRevision, error) { | ||
| 195 | for _, cand := range candidates(rev) { | 195 | for _, cand := range candidates(rev) { | ||
| 196 | h, err := c.info(cand.spec) | 196 | h, err := c.info(cand.spec) | ||
| @@ -213,8 +213,6 @@ func resolve(c *catConn, rev domain.Revision) (domain.ResolvedRevision, error) { | |||||
| 213 | } | 213 | } | ||
| 214 | 214 | ||||
| 215 | // ResolveRevision resolves a revision with `cat-file`. | 215 | // ResolveRevision resolves a revision with `cat-file`. | ||
| 216 | - | // | |||
| 217 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |||
| 218 | func (g *Git) ResolveRevision(ctx context.Context, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | 216 | func (g *Git) ResolveRevision(ctx context.Context, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | ||
| 219 | dir, err := g.repoDir(repo) | 217 | dir, err := g.repoDir(repo) | ||
| 220 | if err != nil { | 218 | if err != nil { | ||
| @@ -235,8 +233,6 @@ func (g *Git) ResolveRevision(ctx context.Context, repo domain.RepoName, rev dom | |||||
| 235 | // tag, full ref name, HEAD; a single segment may also be a commit id), longest | 233 | // tag, full ref name, HEAD; a single segment may also be a commit id), longest | ||
| 236 | // first, with up to one `cat-file` request per candidate on the repository's | 234 | // first, with up to one `cat-file` request per candidate on the repository's | ||
| 237 | // process. At most domain.MaxRefPathTries segments are tried. | 235 | // process. At most domain.MaxRefPathTries segments are tried. | ||
| 238 | - | // | |||
| 239 | - | //hexcheck:ignore suspicious-business-logic-in-adapter the split is domain.SplitRefPath; this only runs it on a cat-file connection | |||
| 240 | func (g *Git) ResolveRefPath(ctx context.Context, repo domain.RepoName, path string) (domain.RefPath, error) { | 236 | func (g *Git) ResolveRefPath(ctx context.Context, repo domain.RepoName, path string) (domain.RefPath, error) { | ||
| 241 | dir, err := g.repoDir(repo) | 237 | dir, err := g.repoDir(repo) | ||
| 242 | if err != nil { | 238 | if err != nil { | ||
| @@ -264,6 +260,8 @@ type object struct { | |||||
| 264 | // lookup resolves rev and reads the header of the object at path, in one | 260 | // lookup resolves rev and reads the header of the object at path, in one | ||
| 265 | // request series on the repository's process. A missing path is | 261 | // request series on the repository's process. A missing path is | ||
| 266 | // domain.ErrNotFound. | 262 | // domain.ErrNotFound. | ||
| 263 | + | // | |||
| 264 | + | //hexcheck:ignore suspicious-business-logic-in-adapter uses the business rule for revision resolution order, pending move to domain.Revision in a follow-up, before looking up a path | |||
| 267 | func (g *Git) lookup(ctx context.Context, dir string, rev domain.Revision, path domain.TreePath) (object, error) { | 265 | func (g *Git) lookup(ctx context.Context, dir string, rev domain.Revision, path domain.TreePath) (object, error) { | ||
| 268 | var obj object | 266 | var obj object | ||
| 269 | err := g.cat.do(ctx, dir, func(c *catConn) error { | 267 | err := g.cat.do(ctx, dir, func(c *catConn) error { | ||
| @@ -392,8 +390,6 @@ func (g *Git) GetTree(ctx context.Context, repo domain.RepoName, rev domain.Revi | |||||
| 392 | } | 390 | } | ||
| 393 | 391 | ||||
| 394 | // parseTreeEntry parses "<mode> <type> <id> <size>\t<name>" of ls-tree -l. | 392 | // parseTreeEntry parses "<mode> <type> <id> <size>\t<name>" of ls-tree -l. | ||
| 395 | - | // | |||
| 396 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |||
| 397 | func parseTreeEntry(rec string, parent domain.TreePath) (domain.TreeEntry, error) { | 393 | func parseTreeEntry(rec string, parent domain.TreePath) (domain.TreeEntry, error) { | ||
| 398 | meta, name, ok := strings.Cut(rec, "\t") | 394 | meta, name, ok := strings.Cut(rec, "\t") | ||
| 399 | f := strings.Fields(meta) | 395 | f := strings.Fields(meta) | ||
| @@ -487,8 +483,6 @@ feed: | |||||
| 487 | 483 | ||||
| 488 | // lastCommit returns the newest commit reachable from head that changed path; | 484 | // lastCommit returns the newest commit reachable from head that changed path; | ||
| 489 | // an empty path means head itself. | 485 | // an empty path means head itself. | ||
| 490 | - | // | |||
| 491 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |||
| 492 | func (g *Git) lastCommit(ctx context.Context, dir string, head domain.ObjectID, path string) (domain.Commit, error) { | 486 | func (g *Git) lastCommit(ctx context.Context, dir string, head domain.ObjectID, path string) (domain.Commit, error) { | ||
| 493 | var c domain.Commit | 487 | var c domain.Commit | ||
| 494 | found := false | 488 | found := false | ||
| @@ -520,8 +514,6 @@ const commitFormat = "%H%x00%P%x00%an%x00%ae%x00%at%x00%cn%x00%ce%x00%ct%x00%B" | |||||
| 520 | 514 | ||||
| 521 | // readCommit reads one commit in commitFormat. It returns io.EOF at the end | 515 | // readCommit reads one commit in commitFormat. It returns io.EOF at the end | ||
| 522 | // of the output. | 516 | // of the output. | ||
| 523 | - | // | |||
| 524 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses git output into domain values; limits and rules come from the port | |||
| 525 | func readCommit(r *bufio.Reader) (domain.Commit, error) { | 517 | func readCommit(r *bufio.Reader) (domain.Commit, error) { | ||
| 526 | var f [9]string | 518 | var f [9]string | ||
| 527 | for i := range f { | 519 | for i := range f { | ||
M internal/adapters/gitcli/repos.go +1 -3
| @@ -102,7 +102,7 @@ func (g *Git) Discard(_ context.Context, id ports.StagedID) error { | |||
| 102 | 102 | ||
| 103 | 103 | // PurgeStaging removes everything under repos/.staging/. | |
| 104 | 104 | // | |
| 105 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |
| 105 | + | //hexcheck:ignore suspicious-business-logic-in-adapter removes staging leftovers from disk, tolerates a missing directory, and logs each removal | |
| 106 | 106 | func (g *Git) PurgeStaging(ctx context.Context) error { | |
| 107 | 107 | entries, err := os.ReadDir(g.stagingDir()) | |
| 108 | 108 | if err != nil { | |
| @@ -280,8 +280,6 @@ func (g *Git) DefaultBranch(ctx context.Context, name domain.RepoName) (string, | |||
| 280 | 280 | // HasBranch checks refs/heads/<branch> with `git for-each-ref` after | |
| 281 | 281 | // `git check-ref-format`, which rejects the glob characters for-each-ref | |
| 282 | 282 | // would otherwise interpret. | |
| 283 | - | // | |
| 284 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |
| 285 | 283 | func (g *Git) HasBranch(ctx context.Context, name domain.RepoName, branch string) (bool, error) { | |
| 286 | 284 | dir, err := g.repoDir(name) | |
| 287 | 285 | if err != nil { | |
| @@ -102,7 +102,7 @@ func (g *Git) Discard(_ context.Context, id ports.StagedID) error { | |||||
| 102 | 102 | ||||
| 103 | // PurgeStaging removes everything under repos/.staging/. | 103 | // PurgeStaging removes everything under repos/.staging/. | ||
| 104 | // | 104 | // | ||
| 105 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | 105 | + | //hexcheck:ignore suspicious-business-logic-in-adapter removes staging leftovers from disk, tolerates a missing directory, and logs each removal |
| 106 | func (g *Git) PurgeStaging(ctx context.Context) error { | 106 | func (g *Git) PurgeStaging(ctx context.Context) error { | ||
| 107 | entries, err := os.ReadDir(g.stagingDir()) | 107 | entries, err := os.ReadDir(g.stagingDir()) | ||
| 108 | if err != nil { | 108 | if err != nil { | ||
| @@ -280,8 +280,6 @@ func (g *Git) DefaultBranch(ctx context.Context, name domain.RepoName) (string, | |||||
| 280 | // HasBranch checks refs/heads/<branch> with `git for-each-ref` after | 280 | // HasBranch checks refs/heads/<branch> with `git for-each-ref` after | ||
| 281 | // `git check-ref-format`, which rejects the glob characters for-each-ref | 281 | // `git check-ref-format`, which rejects the glob characters for-each-ref | ||
| 282 | // would otherwise interpret. | 282 | // would otherwise interpret. | ||
| 283 | - | // | |||
| 284 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |||
| 285 | func (g *Git) HasBranch(ctx context.Context, name domain.RepoName, branch string) (bool, error) { | 283 | func (g *Git) HasBranch(ctx context.Context, name domain.RepoName, branch string) (bool, error) { | ||
| 286 | dir, err := g.repoDir(name) | 284 | dir, err := g.repoDir(name) | ||
| 287 | if err != nil { | 285 | if err != nil { | ||
M internal/adapters/gitcli/stats.go +0 -6
| @@ -18,8 +18,6 @@ import ( | |||
| 18 | 18 | ||
| 19 | 19 | // CountCommits runs `git rev-list --count`, from the commit graph when the | |
| 20 | 20 | // repository has one. | |
| 21 | - | // | |
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the count git prints | |
| 23 | 21 | func (g *Git) CountCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID) (int, error) { | |
| 24 | 22 | if head.IsZero() { | |
| 25 | 23 | return 0, fmt.Errorf("count commits: %w: no head", domain.ErrInvalid) | |
| @@ -45,8 +43,6 @@ func (g *Git) CountCommits(ctx context.Context, repo domain.RepoName, head domai | |||
| 45 | 43 | // CommitTimes runs `git rev-list --since-as-filter --format=%ct`. The filter | |
| 46 | 44 | // looks at every reachable commit: --since stops the walk at the first older | |
| 47 | 45 | // one, and misses newer commits behind it when dates are out of order. | |
| 48 | - | // | |
| 49 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the dates git prints; the bound comes from the port | |
| 50 | 46 | func (g *Git) CommitTimes(ctx context.Context, repo domain.RepoName, head domain.ObjectID, since time.Time) ([]time.Time, bool, error) { | |
| 51 | 47 | if head.IsZero() { | |
| 52 | 48 | return nil, false, fmt.Errorf("commit times: %w: no head", domain.ErrInvalid) | |
| @@ -91,8 +87,6 @@ func (g *Git) CommitTimes(ctx context.Context, repo domain.RepoName, head domain | |||
| 91 | 87 | } | |
| 92 | 88 | ||
| 93 | 89 | // LatestTag runs `git for-each-ref --sort=-creatordate --count=1` on the tags. | |
| 94 | - | // | |
| 95 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the line git prints | |
| 96 | 90 | func (g *Git) LatestTag(ctx context.Context, repo domain.RepoName) (domain.TagInfo, bool, error) { | |
| 97 | 91 | dir, err := g.repoDir(repo) | |
| 98 | 92 | if err != nil { | |
| @@ -18,8 +18,6 @@ import ( | |||||
| 18 | 18 | ||||
| 19 | // CountCommits runs `git rev-list --count`, from the commit graph when the | 19 | // CountCommits runs `git rev-list --count`, from the commit graph when the | ||
| 20 | // repository has one. | 20 | // repository has one. | ||
| 21 | - | // | |||
| 22 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the count git prints | |||
| 23 | func (g *Git) CountCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID) (int, error) { | 21 | func (g *Git) CountCommits(ctx context.Context, repo domain.RepoName, head domain.ObjectID) (int, error) { | ||
| 24 | if head.IsZero() { | 22 | if head.IsZero() { | ||
| 25 | return 0, fmt.Errorf("count commits: %w: no head", domain.ErrInvalid) | 23 | return 0, fmt.Errorf("count commits: %w: no head", domain.ErrInvalid) | ||
| @@ -45,8 +43,6 @@ func (g *Git) CountCommits(ctx context.Context, repo domain.RepoName, head domai | |||||
| 45 | // CommitTimes runs `git rev-list --since-as-filter --format=%ct`. The filter | 43 | // CommitTimes runs `git rev-list --since-as-filter --format=%ct`. The filter | ||
| 46 | // looks at every reachable commit: --since stops the walk at the first older | 44 | // looks at every reachable commit: --since stops the walk at the first older | ||
| 47 | // one, and misses newer commits behind it when dates are out of order. | 45 | // one, and misses newer commits behind it when dates are out of order. | ||
| 48 | - | // | |||
| 49 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the dates git prints; the bound comes from the port | |||
| 50 | func (g *Git) CommitTimes(ctx context.Context, repo domain.RepoName, head domain.ObjectID, since time.Time) ([]time.Time, bool, error) { | 46 | func (g *Git) CommitTimes(ctx context.Context, repo domain.RepoName, head domain.ObjectID, since time.Time) ([]time.Time, bool, error) { | ||
| 51 | if head.IsZero() { | 47 | if head.IsZero() { | ||
| 52 | return nil, false, fmt.Errorf("commit times: %w: no head", domain.ErrInvalid) | 48 | return nil, false, fmt.Errorf("commit times: %w: no head", domain.ErrInvalid) | ||
| @@ -91,8 +87,6 @@ func (g *Git) CommitTimes(ctx context.Context, repo domain.RepoName, head domain | |||||
| 91 | } | 87 | } | ||
| 92 | 88 | ||||
| 93 | // LatestTag runs `git for-each-ref --sort=-creatordate --count=1` on the tags. | 89 | // LatestTag runs `git for-each-ref --sort=-creatordate --count=1` on the tags. | ||
| 94 | - | // | |||
| 95 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the line git prints | |||
| 96 | func (g *Git) LatestTag(ctx context.Context, repo domain.RepoName) (domain.TagInfo, bool, error) { | 90 | func (g *Git) LatestTag(ctx context.Context, repo domain.RepoName) (domain.TagInfo, bool, error) { | ||
| 97 | dir, err := g.repoDir(repo) | 91 | dir, err := g.repoDir(repo) | ||
| 98 | if err != nil { | 92 | if err != nil { | ||
M internal/adapters/gitcli/workflow_guard.go +1 -1
| @@ -81,7 +81,7 @@ const ( | |||
| 81 | 81 | // objects of a push still in quarantine through the environment of the hook | |
| 82 | 82 | // (ports.PushObjects), accepted only inside the repository's objects directory. | |
| 83 | 83 | // | |
| 84 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the object ids and the path git prints for the compared trees; the rule that refuses is the use case's | |
| 84 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for which pushed commits and ref changes alter workflows; pending move to domain/usecase | |
| 85 | 85 | func (g *Git) ChangedWorkflow(ctx context.Context, repo domain.RepoName, updates []domain.RefUpdate, objects ports.PushObjects) (string, error) { | |
| 86 | 86 | dir, err := g.repoDir(repo) | |
| 87 | 87 | if err != nil { | |
| @@ -81,7 +81,7 @@ const ( | |||||
| 81 | // objects of a push still in quarantine through the environment of the hook | 81 | // objects of a push still in quarantine through the environment of the hook | ||
| 82 | // (ports.PushObjects), accepted only inside the repository's objects directory. | 82 | // (ports.PushObjects), accepted only inside the repository's objects directory. | ||
| 83 | // | 83 | // | ||
| 84 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the object ids and the path git prints for the compared trees; the rule that refuses is the use case's | 84 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule for which pushed commits and ref changes alter workflows; pending move to domain/usecase |
| 85 | func (g *Git) ChangedWorkflow(ctx context.Context, repo domain.RepoName, updates []domain.RefUpdate, objects ports.PushObjects) (string, error) { | 85 | func (g *Git) ChangedWorkflow(ctx context.Context, repo domain.RepoName, updates []domain.RefUpdate, objects ports.PushObjects) (string, error) { | ||
| 86 | dir, err := g.repoDir(repo) | 86 | dir, err := g.repoDir(repo) | ||
| 87 | if err != nil { | 87 | if err != nil { | ||
M internal/adapters/githttp/handler.go +4 -4
| @@ -174,6 +174,8 @@ var gitSuffixes = []string{"/info/refs", "/" + serviceUpload, "/" + serviceRecei | |||
| 174 | 174 | // and /<repo>/git-receive-pack, and the same under /<owner>/ for the owner of | |
| 175 | 175 | // the forge. info/refs without a service is the dumb protocol, which ermite | |
| 176 | 176 | // does not serve. | |
| 177 | + | // | |
| 178 | + | //hexcheck:ignore suspicious-business-logic-in-adapter decodes smart-HTTP repository routes and owner aliases, validating methods and service query parameters | |
| 177 | 179 | func (h *Handler) parseRoute(r *http.Request) (route, int) { | |
| 178 | 180 | p := strings.TrimPrefix(r.URL.Path, "/") | |
| 179 | 181 | var head, rest string | |
| @@ -224,8 +226,6 @@ func (h *Handler) parseRoute(r *http.Request) (route, int) { | |||
| 224 | 226 | } | |
| 225 | 227 | ||
| 226 | 228 | // ServeHTTP implements http.Handler. | |
| 227 | - | // | |
| 228 | - | //hexcheck:ignore suspicious-business-logic-in-adapter transport orchestration: the authorization decisions are the use cases' | |
| 229 | 229 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 230 | 230 | var rt route | |
| 231 | 231 | var name domain.RepoName | |
| @@ -328,6 +328,8 @@ func credentials(r *http.Request) (secret string, present bool) { | |||
| 328 | 328 | // denied answers an authorization failure. A caller without valid | |
| 329 | 329 | // credentials is asked for them wherever the repository does not show itself, | |
| 330 | 330 | // which keeps a private repository and a missing one indistinguishable. | |
| 331 | + | // | |
| 332 | + | //hexcheck:ignore suspicious-business-logic-in-adapter maps authorization errors to HTTP responses, challenging anonymous callers on hidden or missing repositories | |
| 331 | 333 | func (h *Handler) denied(ctx context.Context, w http.ResponseWriter, p domain.Principal, err error) { | |
| 332 | 334 | switch { | |
| 333 | 335 | case errors.Is(err, domain.ErrUnauthenticated): | |
| @@ -418,8 +420,6 @@ func (h *Handler) acquire(ctx context.Context, w http.ResponseWriter, rt route, | |||
| 418 | 420 | } | |
| 419 | 421 | ||
| 420 | 422 | // serveBackend runs git http-backend for an authorized request. | |
| 421 | - | // | |
| 422 | - | //hexcheck:ignore suspicious-business-logic-in-adapter process and CGI plumbing: no business rule is decided here | |
| 423 | 423 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | |
| 424 | 424 | ctx := r.Context() | |
| 425 | 425 | logger := zerowrap.FromCtx(ctx) | |
| @@ -174,6 +174,8 @@ var gitSuffixes = []string{"/info/refs", "/" + serviceUpload, "/" + serviceRecei | |||||
| 174 | // and /<repo>/git-receive-pack, and the same under /<owner>/ for the owner of | 174 | // and /<repo>/git-receive-pack, and the same under /<owner>/ for the owner of | ||
| 175 | // the forge. info/refs without a service is the dumb protocol, which ermite | 175 | // the forge. info/refs without a service is the dumb protocol, which ermite | ||
| 176 | // does not serve. | 176 | // does not serve. | ||
| 177 | + | // | |||
| 178 | + | //hexcheck:ignore suspicious-business-logic-in-adapter decodes smart-HTTP repository routes and owner aliases, validating methods and service query parameters | |||
| 177 | func (h *Handler) parseRoute(r *http.Request) (route, int) { | 179 | func (h *Handler) parseRoute(r *http.Request) (route, int) { | ||
| 178 | p := strings.TrimPrefix(r.URL.Path, "/") | 180 | p := strings.TrimPrefix(r.URL.Path, "/") | ||
| 179 | var head, rest string | 181 | var head, rest string | ||
| @@ -224,8 +226,6 @@ func (h *Handler) parseRoute(r *http.Request) (route, int) { | |||||
| 224 | } | 226 | } | ||
| 225 | 227 | ||||
| 226 | // ServeHTTP implements http.Handler. | 228 | // ServeHTTP implements http.Handler. | ||
| 227 | - | // | |||
| 228 | - | //hexcheck:ignore suspicious-business-logic-in-adapter transport orchestration: the authorization decisions are the use cases' | |||
| 229 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 229 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
| 230 | var rt route | 230 | var rt route | ||
| 231 | var name domain.RepoName | 231 | var name domain.RepoName | ||
| @@ -328,6 +328,8 @@ func credentials(r *http.Request) (secret string, present bool) { | |||||
| 328 | // denied answers an authorization failure. A caller without valid | 328 | // denied answers an authorization failure. A caller without valid | ||
| 329 | // credentials is asked for them wherever the repository does not show itself, | 329 | // credentials is asked for them wherever the repository does not show itself, | ||
| 330 | // which keeps a private repository and a missing one indistinguishable. | 330 | // which keeps a private repository and a missing one indistinguishable. | ||
| 331 | + | // | |||
| 332 | + | //hexcheck:ignore suspicious-business-logic-in-adapter maps authorization errors to HTTP responses, challenging anonymous callers on hidden or missing repositories | |||
| 331 | func (h *Handler) denied(ctx context.Context, w http.ResponseWriter, p domain.Principal, err error) { | 333 | func (h *Handler) denied(ctx context.Context, w http.ResponseWriter, p domain.Principal, err error) { | ||
| 332 | switch { | 334 | switch { | ||
| 333 | case errors.Is(err, domain.ErrUnauthenticated): | 335 | case errors.Is(err, domain.ErrUnauthenticated): | ||
| @@ -418,8 +420,6 @@ func (h *Handler) acquire(ctx context.Context, w http.ResponseWriter, rt route, | |||||
| 418 | } | 420 | } | ||
| 419 | 421 | ||||
| 420 | // serveBackend runs git http-backend for an authorized request. | 422 | // serveBackend runs git http-backend for an authorized request. | ||
| 421 | - | // | |||
| 422 | - | //hexcheck:ignore suspicious-business-logic-in-adapter process and CGI plumbing: no business rule is decided here | |||
| 423 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | 423 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | ||
| 424 | ctx := r.Context() | 424 | ctx := r.Context() | ||
| 425 | logger := zerowrap.FromCtx(ctx) | 425 | logger := zerowrap.FromCtx(ctx) | ||
M internal/adapters/githttp/hooks.go +0 -2
| @@ -175,8 +175,6 @@ func (s *HookServer) Close(ctx context.Context) { | |||
| 175 | 175 | } | |
| 176 | 176 | ||
| 177 | 177 | // handle serves one connection: one request line, one reply line. | |
| 178 | - | // | |
| 179 | - | //hexcheck:ignore suspicious-business-logic-in-adapter hook protocol dispatch: the decisions are the use cases' | |
| 180 | 178 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | |
| 181 | 179 | log := zerowrap.FromCtx(ctx) | |
| 182 | 180 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | |
| @@ -175,8 +175,6 @@ func (s *HookServer) Close(ctx context.Context) { | |||||
| 175 | } | 175 | } | ||
| 176 | 176 | ||||
| 177 | // handle serves one connection: one request line, one reply line. | 177 | // handle serves one connection: one request line, one reply line. | ||
| 178 | - | // | |||
| 179 | - | //hexcheck:ignore suspicious-business-logic-in-adapter hook protocol dispatch: the decisions are the use cases' | |||
| 180 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | 178 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | ||
| 181 | log := zerowrap.FromCtx(ctx) | 179 | log := zerowrap.FromCtx(ctx) | ||
| 182 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | 180 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | ||
M internal/adapters/kvstore/ci.go +4 -11
| @@ -310,6 +310,9 @@ func decodeRun(item kv.Item) (domain.CIRun, error) { | |||
| 310 | 310 | }, nil | |
| 311 | 311 | } | |
| 312 | 312 | ||
| 313 | + | // encodeJob serializes a job for storage. | |
| 314 | + | // | |
| 315 | + | //hexcheck:ignore suspicious-business-logic-in-adapter encodes a job as protobuf, rejecting an empty repository and omitting an absent token hash | |
| 313 | 316 | func encodeJob(j domain.CIJob) ([]byte, error) { | |
| 314 | 317 | if j.Repo.IsZero() { | |
| 315 | 318 | return nil, fmt.Errorf("%w: empty name", domain.ErrInvalidName) | |
| @@ -346,7 +349,6 @@ func encodeJob(j domain.CIJob) ([]byte, error) { | |||
| 346 | 349 | return mustMarshal(pb), nil | |
| 347 | 350 | } | |
| 348 | 351 | ||
| 349 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored record to the domain job field by field: no rule is decided here | |
| 350 | 352 | func decodeJob(item kv.Item) (domain.CIJob, error) { | |
| 351 | 353 | var pb storagepb.CIJob | |
| 352 | 354 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -530,8 +532,6 @@ func (c *CI) stageRecords(ctx context.Context, b *kv.Batch, w ports.CIWrite) (gu | |||
| 530 | 532 | } | |
| 531 | 533 | ||
| 532 | 534 | // Apply writes the records in one batch. | |
| 533 | - | // | |
| 534 | - | //hexcheck:ignore suspicious-business-logic-in-adapter stages records and their derived indexes under version preconditions: a storage concern, no policy | |
| 535 | 535 | func (c *CI) Apply(ctx context.Context, w ports.CIWrite) (uint64, error) { | |
| 536 | 536 | var b kv.Batch | |
| 537 | 537 | guarded, err := c.stageRecords(ctx, &b, w) | |
| @@ -578,7 +578,7 @@ const createRunTries = 20 | |||
| 578 | 578 | ||
| 579 | 579 | // CreateRun takes the next run id and number and stores the draft. | |
| 580 | 580 | // | |
| 581 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next numbers under version preconditions: a storage concern, no policy | |
| 581 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule rejecting runs of disabled workflows, atomically with creation; pending move to domain/usecase | |
| 582 | 582 | func (c *CI) CreateRun(ctx context.Context, repo domain.RepoName, workflowPath string, build func(id, number int64) ports.CIRunDraft) (ports.CIRunDraft, error) { | |
| 583 | 583 | offKey := workflowOffKey(repo, workflowPath) | |
| 584 | 584 | for range createRunTries { | |
| @@ -669,8 +669,6 @@ func (c *CI) GetRunSource(ctx context.Context, runID int64) (domain.CIRunSource, | |||
| 669 | 669 | } | |
| 670 | 670 | ||
| 671 | 671 | // ListRuns returns the runs of the repository, newest first. | |
| 672 | - | // | |
| 673 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only: reads a key range and reverses it | |
| 674 | 672 | func (c *CI) ListRuns(ctx context.Context, repo domain.RepoName, before int64, limit int) ([]domain.CIRun, error) { | |
| 675 | 673 | start := []byte(runsPrefix(repo)) | |
| 676 | 674 | end := []byte(runPrefix + repo.String() + "0") // '/' + 1 | |
| @@ -906,8 +904,6 @@ func ciKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) [][]by | |||
| 906 | 904 | const sweepChunk = 500 | |
| 907 | 905 | ||
| 908 | 906 | // Sweep removes the runs completed before the time. | |
| 909 | - | // | |
| 910 | - | //hexcheck:ignore suspicious-business-logic-in-adapter chunked delete of expired records: a storage concern, the retention is decided by the caller | |
| 911 | 907 | func (c *CI) Sweep(ctx context.Context, before time.Time) ([]int64, error) { | |
| 912 | 908 | snap := c.db.Snapshot(ctx) | |
| 913 | 909 | var ids []int64 | |
| @@ -955,8 +951,6 @@ func runnerNameKey(n string) []byte { return []byte(runnerName + stri | |||
| 955 | 951 | func runnerTokenKey(h domain.TokenHash) []byte { return []byte(runnerTokPref + h.String()) } | |
| 956 | 952 | ||
| 957 | 953 | // CreateRunner stores the runner, its name index and its token index. | |
| 958 | - | // | |
| 959 | - | //hexcheck:ignore suspicious-business-logic-in-adapter replaces a runner of the same name in one batch: a storage concern, the rule is decided by the caller | |
| 960 | 954 | func (c *CI) CreateRunner(ctx context.Context, r domain.CIRunner, replace bool) ([]domain.CIRunner, error) { | |
| 961 | 955 | for range createRunTries { | |
| 962 | 956 | var b kv.Batch | |
| @@ -1115,7 +1109,6 @@ func encodeCall(c *domain.CICall) *storagepb.CICall { | |||
| 1115 | 1109 | } | |
| 1116 | 1110 | } | |
| 1117 | 1111 | ||
| 1118 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored call to the domain call field by field: no rule is decided here | |
| 1119 | 1112 | func decodeCall(pb *storagepb.CICall) *domain.CICall { | |
| 1120 | 1113 | if pb == nil { | |
| 1121 | 1114 | return nil | |
| @@ -310,6 +310,9 @@ func decodeRun(item kv.Item) (domain.CIRun, error) { | |||||
| 310 | }, nil | 310 | }, nil | ||
| 311 | } | 311 | } | ||
| 312 | 312 | ||||
| 313 | + | // encodeJob serializes a job for storage. | |||
| 314 | + | // | |||
| 315 | + | //hexcheck:ignore suspicious-business-logic-in-adapter encodes a job as protobuf, rejecting an empty repository and omitting an absent token hash | |||
| 313 | func encodeJob(j domain.CIJob) ([]byte, error) { | 316 | func encodeJob(j domain.CIJob) ([]byte, error) { | ||
| 314 | if j.Repo.IsZero() { | 317 | if j.Repo.IsZero() { | ||
| 315 | return nil, fmt.Errorf("%w: empty name", domain.ErrInvalidName) | 318 | return nil, fmt.Errorf("%w: empty name", domain.ErrInvalidName) | ||
| @@ -346,7 +349,6 @@ func encodeJob(j domain.CIJob) ([]byte, error) { | |||||
| 346 | return mustMarshal(pb), nil | 349 | return mustMarshal(pb), nil | ||
| 347 | } | 350 | } | ||
| 348 | 351 | ||||
| 349 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored record to the domain job field by field: no rule is decided here | |||
| 350 | func decodeJob(item kv.Item) (domain.CIJob, error) { | 352 | func decodeJob(item kv.Item) (domain.CIJob, error) { | ||
| 351 | var pb storagepb.CIJob | 353 | var pb storagepb.CIJob | ||
| 352 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 354 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
| @@ -530,8 +532,6 @@ func (c *CI) stageRecords(ctx context.Context, b *kv.Batch, w ports.CIWrite) (gu | |||||
| 530 | } | 532 | } | ||
| 531 | 533 | ||||
| 532 | // Apply writes the records in one batch. | 534 | // Apply writes the records in one batch. | ||
| 533 | - | // | |||
| 534 | - | //hexcheck:ignore suspicious-business-logic-in-adapter stages records and their derived indexes under version preconditions: a storage concern, no policy | |||
| 535 | func (c *CI) Apply(ctx context.Context, w ports.CIWrite) (uint64, error) { | 535 | func (c *CI) Apply(ctx context.Context, w ports.CIWrite) (uint64, error) { | ||
| 536 | var b kv.Batch | 536 | var b kv.Batch | ||
| 537 | guarded, err := c.stageRecords(ctx, &b, w) | 537 | guarded, err := c.stageRecords(ctx, &b, w) | ||
| @@ -578,7 +578,7 @@ const createRunTries = 20 | |||||
| 578 | 578 | ||||
| 579 | // CreateRun takes the next run id and number and stores the draft. | 579 | // CreateRun takes the next run id and number and stores the draft. | ||
| 580 | // | 580 | // | ||
| 581 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next numbers under version preconditions: a storage concern, no policy | 581 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule rejecting runs of disabled workflows, atomically with creation; pending move to domain/usecase |
| 582 | func (c *CI) CreateRun(ctx context.Context, repo domain.RepoName, workflowPath string, build func(id, number int64) ports.CIRunDraft) (ports.CIRunDraft, error) { | 582 | func (c *CI) CreateRun(ctx context.Context, repo domain.RepoName, workflowPath string, build func(id, number int64) ports.CIRunDraft) (ports.CIRunDraft, error) { | ||
| 583 | offKey := workflowOffKey(repo, workflowPath) | 583 | offKey := workflowOffKey(repo, workflowPath) | ||
| 584 | for range createRunTries { | 584 | for range createRunTries { | ||
| @@ -669,8 +669,6 @@ func (c *CI) GetRunSource(ctx context.Context, runID int64) (domain.CIRunSource, | |||||
| 669 | } | 669 | } | ||
| 670 | 670 | ||||
| 671 | // ListRuns returns the runs of the repository, newest first. | 671 | // ListRuns returns the runs of the repository, newest first. | ||
| 672 | - | // | |||
| 673 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only: reads a key range and reverses it | |||
| 674 | func (c *CI) ListRuns(ctx context.Context, repo domain.RepoName, before int64, limit int) ([]domain.CIRun, error) { | 672 | func (c *CI) ListRuns(ctx context.Context, repo domain.RepoName, before int64, limit int) ([]domain.CIRun, error) { | ||
| 675 | start := []byte(runsPrefix(repo)) | 673 | start := []byte(runsPrefix(repo)) | ||
| 676 | end := []byte(runPrefix + repo.String() + "0") // '/' + 1 | 674 | end := []byte(runPrefix + repo.String() + "0") // '/' + 1 | ||
| @@ -906,8 +904,6 @@ func ciKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) [][]by | |||||
| 906 | const sweepChunk = 500 | 904 | const sweepChunk = 500 | ||
| 907 | 905 | ||||
| 908 | // Sweep removes the runs completed before the time. | 906 | // Sweep removes the runs completed before the time. | ||
| 909 | - | // | |||
| 910 | - | //hexcheck:ignore suspicious-business-logic-in-adapter chunked delete of expired records: a storage concern, the retention is decided by the caller | |||
| 911 | func (c *CI) Sweep(ctx context.Context, before time.Time) ([]int64, error) { | 907 | func (c *CI) Sweep(ctx context.Context, before time.Time) ([]int64, error) { | ||
| 912 | snap := c.db.Snapshot(ctx) | 908 | snap := c.db.Snapshot(ctx) | ||
| 913 | var ids []int64 | 909 | var ids []int64 | ||
| @@ -955,8 +951,6 @@ func runnerNameKey(n string) []byte { return []byte(runnerName + stri | |||||
| 955 | func runnerTokenKey(h domain.TokenHash) []byte { return []byte(runnerTokPref + h.String()) } | 951 | func runnerTokenKey(h domain.TokenHash) []byte { return []byte(runnerTokPref + h.String()) } | ||
| 956 | 952 | ||||
| 957 | // CreateRunner stores the runner, its name index and its token index. | 953 | // CreateRunner stores the runner, its name index and its token index. | ||
| 958 | - | // | |||
| 959 | - | //hexcheck:ignore suspicious-business-logic-in-adapter replaces a runner of the same name in one batch: a storage concern, the rule is decided by the caller | |||
| 960 | func (c *CI) CreateRunner(ctx context.Context, r domain.CIRunner, replace bool) ([]domain.CIRunner, error) { | 954 | func (c *CI) CreateRunner(ctx context.Context, r domain.CIRunner, replace bool) ([]domain.CIRunner, error) { | ||
| 961 | for range createRunTries { | 955 | for range createRunTries { | ||
| 962 | var b kv.Batch | 956 | var b kv.Batch | ||
| @@ -1115,7 +1109,6 @@ func encodeCall(c *domain.CICall) *storagepb.CICall { | |||||
| 1115 | } | 1109 | } | ||
| 1116 | } | 1110 | } | ||
| 1117 | 1111 | ||||
| 1118 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored call to the domain call field by field: no rule is decided here | |||
| 1119 | func decodeCall(pb *storagepb.CICall) *domain.CICall { | 1112 | func decodeCall(pb *storagepb.CICall) *domain.CICall { | ||
| 1120 | if pb == nil { | 1113 | if pb == nil { | ||
| 1121 | return nil | 1114 | return nil | ||
M internal/adapters/kvstore/ci_artifact.go +3 -5
| @@ -79,6 +79,9 @@ var artifactStates = []struct { | |||
| 79 | 79 | {domain.CIArtifactFinal, storagepb.CIArtifactState_CI_ARTIFACT_STATE_FINAL}, | |
| 80 | 80 | } | |
| 81 | 81 | ||
| 82 | + | // encodeArtifact serializes an artifact for storage. | |
| 83 | + | // | |
| 84 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates artifact storage identifiers, UTF-8 and enum encoding before protobuf serialization | |
| 82 | 85 | func encodeArtifact(a domain.CIArtifact) ([]byte, error) { | |
| 83 | 86 | if a.Repo.IsZero() || a.ID < 1 || a.RunID < 1 { | |
| 84 | 87 | return nil, fmt.Errorf("%w: artifact without id, run or repository", domain.ErrInvalid) | |
| @@ -106,7 +109,6 @@ func encodeArtifact(a domain.CIArtifact) ([]byte, error) { | |||
| 106 | 109 | return mustMarshal(pb), nil | |
| 107 | 110 | } | |
| 108 | 111 | ||
| 109 | - | //hexcheck:ignore suspicious-business-logic-in-adapter decodes a record into the domain type: a storage concern, no policy | |
| 110 | 112 | func decodeArtifact(item kv.Item) (domain.CIArtifact, error) { | |
| 111 | 113 | var pb storagepb.CIArtifact | |
| 112 | 114 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -141,8 +143,6 @@ func decodeArtifact(item kv.Item) (domain.CIArtifact, error) { | |||
| 141 | 143 | const artifactIDTries = 1000 | |
| 142 | 144 | ||
| 143 | 145 | // NextArtifactID takes the next id in its own batch. | |
| 144 | - | // | |
| 145 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |
| 146 | 146 | func (c *CIArtifacts) NextArtifactID(ctx context.Context) (int64, error) { | |
| 147 | 147 | ci := &CI{db: c.db} | |
| 148 | 148 | for range artifactIDTries { | |
| @@ -274,8 +274,6 @@ func (c *CIArtifacts) BlockArtifactIDs(ctx context.Context) ([]int64, error) { | |||
| 274 | 274 | // --- writes --- | |
| 275 | 275 | ||
| 276 | 276 | // ApplyArtifacts writes w in one batch. | |
| 277 | - | // | |
| 278 | - | //hexcheck:ignore suspicious-business-logic-in-adapter stages records and their derived keys under version preconditions: a storage concern, no policy | |
| 279 | 277 | func (c *CIArtifacts) ApplyArtifacts(ctx context.Context, w ports.CIArtifactWrite) error { | |
| 280 | 278 | var b kv.Batch | |
| 281 | 279 | guard := false | |
| @@ -79,6 +79,9 @@ var artifactStates = []struct { | |||||
| 79 | {domain.CIArtifactFinal, storagepb.CIArtifactState_CI_ARTIFACT_STATE_FINAL}, | 79 | {domain.CIArtifactFinal, storagepb.CIArtifactState_CI_ARTIFACT_STATE_FINAL}, | ||
| 80 | } | 80 | } | ||
| 81 | 81 | ||||
| 82 | + | // encodeArtifact serializes an artifact for storage. | |||
| 83 | + | // | |||
| 84 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates artifact storage identifiers, UTF-8 and enum encoding before protobuf serialization | |||
| 82 | func encodeArtifact(a domain.CIArtifact) ([]byte, error) { | 85 | func encodeArtifact(a domain.CIArtifact) ([]byte, error) { | ||
| 83 | if a.Repo.IsZero() || a.ID < 1 || a.RunID < 1 { | 86 | if a.Repo.IsZero() || a.ID < 1 || a.RunID < 1 { | ||
| 84 | return nil, fmt.Errorf("%w: artifact without id, run or repository", domain.ErrInvalid) | 87 | return nil, fmt.Errorf("%w: artifact without id, run or repository", domain.ErrInvalid) | ||
| @@ -106,7 +109,6 @@ func encodeArtifact(a domain.CIArtifact) ([]byte, error) { | |||||
| 106 | return mustMarshal(pb), nil | 109 | return mustMarshal(pb), nil | ||
| 107 | } | 110 | } | ||
| 108 | 111 | ||||
| 109 | - | //hexcheck:ignore suspicious-business-logic-in-adapter decodes a record into the domain type: a storage concern, no policy | |||
| 110 | func decodeArtifact(item kv.Item) (domain.CIArtifact, error) { | 112 | func decodeArtifact(item kv.Item) (domain.CIArtifact, error) { | ||
| 111 | var pb storagepb.CIArtifact | 113 | var pb storagepb.CIArtifact | ||
| 112 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 114 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
| @@ -141,8 +143,6 @@ func decodeArtifact(item kv.Item) (domain.CIArtifact, error) { | |||||
| 141 | const artifactIDTries = 1000 | 143 | const artifactIDTries = 1000 | ||
| 142 | 144 | ||||
| 143 | // NextArtifactID takes the next id in its own batch. | 145 | // NextArtifactID takes the next id in its own batch. | ||
| 144 | - | // | |||
| 145 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |||
| 146 | func (c *CIArtifacts) NextArtifactID(ctx context.Context) (int64, error) { | 146 | func (c *CIArtifacts) NextArtifactID(ctx context.Context) (int64, error) { | ||
| 147 | ci := &CI{db: c.db} | 147 | ci := &CI{db: c.db} | ||
| 148 | for range artifactIDTries { | 148 | for range artifactIDTries { | ||
| @@ -274,8 +274,6 @@ func (c *CIArtifacts) BlockArtifactIDs(ctx context.Context) ([]int64, error) { | |||||
| 274 | // --- writes --- | 274 | // --- writes --- | ||
| 275 | 275 | ||||
| 276 | // ApplyArtifacts writes w in one batch. | 276 | // ApplyArtifacts writes w in one batch. | ||
| 277 | - | // | |||
| 278 | - | //hexcheck:ignore suspicious-business-logic-in-adapter stages records and their derived keys under version preconditions: a storage concern, no policy | |||
| 279 | func (c *CIArtifacts) ApplyArtifacts(ctx context.Context, w ports.CIArtifactWrite) error { | 277 | func (c *CIArtifacts) ApplyArtifacts(ctx context.Context, w ports.CIArtifactWrite) error { | ||
| 280 | var b kv.Batch | 278 | var b kv.Batch | ||
| 281 | guard := false | 279 | guard := false | ||
M internal/adapters/kvstore/ci_concurrency.go +0 -4
| @@ -103,7 +103,6 @@ func encodeConcurrencyRecord(r domain.CIConcurrencyRecord) []byte { | |||
| 103 | 103 | return mustMarshal(pb) | |
| 104 | 104 | } | |
| 105 | 105 | ||
| 106 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored record to the domain record field by field: no rule is decided here | |
| 107 | 106 | func decodeConcurrencyRecord(val []byte) (domain.CIConcurrencyRecord, error) { | |
| 108 | 107 | var pb storagepb.CIConcurrencyRecord | |
| 109 | 108 | if err := proto.Unmarshal(val, &pb); err != nil { | |
| @@ -146,7 +145,6 @@ func encodeConcurrencyMark(m domain.CIConcurrencyMark) []byte { | |||
| 146 | 145 | return mustMarshal(pb) | |
| 147 | 146 | } | |
| 148 | 147 | ||
| 149 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored mark to the domain mark field by field: no rule is decided here | |
| 150 | 148 | func decodeConcurrencyMark(val []byte) (domain.CIConcurrencyMark, error) { | |
| 151 | 149 | var pb storagepb.CIConcurrencyMark | |
| 152 | 150 | if err := proto.Unmarshal(val, &pb); err != nil { | |
| @@ -257,8 +255,6 @@ func (c *CI) UpdateConcurrency(ctx context.Context, repo domain.RepoName, group | |||
| 257 | 255 | } | |
| 258 | 256 | ||
| 259 | 257 | // ListConcurrency returns every stored group with its marks. | |
| 260 | - | // | |
| 261 | - | //hexcheck:ignore suspicious-business-logic-in-adapter lists and decodes records and marks: no rule is decided here | |
| 262 | 258 | func (c *CI) ListConcurrency(ctx context.Context) ([]ports.CIConcurrencyGroup, error) { | |
| 263 | 259 | type id struct{ repo, group string } | |
| 264 | 260 | snap := c.db.Snapshot(ctx) | |
| @@ -103,7 +103,6 @@ func encodeConcurrencyRecord(r domain.CIConcurrencyRecord) []byte { | |||||
| 103 | return mustMarshal(pb) | 103 | return mustMarshal(pb) | ||
| 104 | } | 104 | } | ||
| 105 | 105 | ||||
| 106 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored record to the domain record field by field: no rule is decided here | |||
| 107 | func decodeConcurrencyRecord(val []byte) (domain.CIConcurrencyRecord, error) { | 106 | func decodeConcurrencyRecord(val []byte) (domain.CIConcurrencyRecord, error) { | ||
| 108 | var pb storagepb.CIConcurrencyRecord | 107 | var pb storagepb.CIConcurrencyRecord | ||
| 109 | if err := proto.Unmarshal(val, &pb); err != nil { | 108 | if err := proto.Unmarshal(val, &pb); err != nil { | ||
| @@ -146,7 +145,6 @@ func encodeConcurrencyMark(m domain.CIConcurrencyMark) []byte { | |||||
| 146 | return mustMarshal(pb) | 145 | return mustMarshal(pb) | ||
| 147 | } | 146 | } | ||
| 148 | 147 | ||||
| 149 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the stored mark to the domain mark field by field: no rule is decided here | |||
| 150 | func decodeConcurrencyMark(val []byte) (domain.CIConcurrencyMark, error) { | 148 | func decodeConcurrencyMark(val []byte) (domain.CIConcurrencyMark, error) { | ||
| 151 | var pb storagepb.CIConcurrencyMark | 149 | var pb storagepb.CIConcurrencyMark | ||
| 152 | if err := proto.Unmarshal(val, &pb); err != nil { | 150 | if err := proto.Unmarshal(val, &pb); err != nil { | ||
| @@ -257,8 +255,6 @@ func (c *CI) UpdateConcurrency(ctx context.Context, repo domain.RepoName, group | |||||
| 257 | } | 255 | } | ||
| 258 | 256 | ||||
| 259 | // ListConcurrency returns every stored group with its marks. | 257 | // ListConcurrency returns every stored group with its marks. | ||
| 260 | - | // | |||
| 261 | - | //hexcheck:ignore suspicious-business-logic-in-adapter lists and decodes records and marks: no rule is decided here | |||
| 262 | func (c *CI) ListConcurrency(ctx context.Context) ([]ports.CIConcurrencyGroup, error) { | 258 | func (c *CI) ListConcurrency(ctx context.Context) ([]ports.CIConcurrencyGroup, error) { | ||
| 263 | type id struct{ repo, group string } | 259 | type id struct{ repo, group string } | ||
| 264 | snap := c.db.Snapshot(ctx) | 260 | snap := c.db.Snapshot(ctx) | ||
M internal/adapters/kvstore/ci_settings.go +6 -4
| @@ -85,6 +85,8 @@ func settingsKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) | |||
| 85 | 85 | ||
| 86 | 86 | // BindSecretsKey stores the key check when there is none and compares it | |
| 87 | 87 | // otherwise. | |
| 88 | + | // | |
| 89 | + | //hexcheck:ignore suspicious-business-logic-in-adapter initializes or compares the persisted encryption-key check with compare-and-swap retries | |
| 88 | 90 | func (s *Settings) BindSecretsKey(ctx context.Context, check []byte) error { | |
| 89 | 91 | key := []byte(secretsKeyCheck) | |
| 90 | 92 | for range updateAttempts { | |
| @@ -111,6 +113,8 @@ func (s *Settings) BindSecretsKey(ctx context.Context, check []byte) error { | |||
| 111 | 113 | ||
| 112 | 114 | // stage makes the batch depend on the scope: the repository key is guarded | |
| 113 | 115 | // and, for an environment, its record is required at the version read. | |
| 116 | + | // | |
| 117 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates a settings scope and adds repository and environment existence/version preconditions to a storage batch | |
| 114 | 118 | func (s *Settings) stage(ctx context.Context, b *kv.Batch, scope domain.SettingsScope) error { | |
| 115 | 119 | if !scope.Valid() { | |
| 116 | 120 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | |
| @@ -203,6 +207,8 @@ func (s *Settings) GetSealedSecret(ctx context.Context, scope domain.SettingsSco | |||
| 203 | 207 | } | |
| 204 | 208 | ||
| 205 | 209 | // existsIn is exists on a snapshot, so a listing and its check agree. | |
| 210 | + | // | |
| 211 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates a settings scope and checks repository and environment keys in the same snapshot as a listing | |
| 206 | 212 | func (s *Settings) existsIn(ctx context.Context, snap *kv.Snapshot, scope domain.SettingsScope) error { | |
| 207 | 213 | if !scope.Valid() { | |
| 208 | 214 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | |
| @@ -309,8 +315,6 @@ func decodeEnvironment(val []byte) (domain.Environment, error) { | |||
| 309 | 315 | } | |
| 310 | 316 | ||
| 311 | 317 | // CreateEnvironment implements ports.CISettingsStore. | |
| 312 | - | // | |
| 313 | - | //hexcheck:ignore suspicious-business-logic-in-adapter create-if-absent under a version precondition: a storage concern, no policy | |
| 314 | 318 | func (s *Settings) CreateEnvironment(ctx context.Context, repo domain.RepoName, name string, at time.Time) (domain.Environment, error) { | |
| 315 | 319 | key := envKey(repo, name) | |
| 316 | 320 | for range updateAttempts { | |
| @@ -353,8 +357,6 @@ func (s *Settings) ListEnvironments(ctx context.Context, repo domain.RepoName) ( | |||
| 353 | 357 | } | |
| 354 | 358 | ||
| 355 | 359 | // DeleteEnvironment implements ports.CISettingsStore. | |
| 356 | - | // | |
| 357 | - | //hexcheck:ignore suspicious-business-logic-in-adapter removes the keys of an environment in one batch: a storage concern, no policy | |
| 358 | 360 | func (s *Settings) DeleteEnvironment(ctx context.Context, repo domain.RepoName, name string) error { | |
| 359 | 361 | key := envKey(repo, name) | |
| 360 | 362 | scope := domain.EnvironmentScope(repo, name) | |
| @@ -85,6 +85,8 @@ func settingsKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) | |||||
| 85 | 85 | ||||
| 86 | // BindSecretsKey stores the key check when there is none and compares it | 86 | // BindSecretsKey stores the key check when there is none and compares it | ||
| 87 | // otherwise. | 87 | // otherwise. | ||
| 88 | + | // | |||
| 89 | + | //hexcheck:ignore suspicious-business-logic-in-adapter initializes or compares the persisted encryption-key check with compare-and-swap retries | |||
| 88 | func (s *Settings) BindSecretsKey(ctx context.Context, check []byte) error { | 90 | func (s *Settings) BindSecretsKey(ctx context.Context, check []byte) error { | ||
| 89 | key := []byte(secretsKeyCheck) | 91 | key := []byte(secretsKeyCheck) | ||
| 90 | for range updateAttempts { | 92 | for range updateAttempts { | ||
| @@ -111,6 +113,8 @@ func (s *Settings) BindSecretsKey(ctx context.Context, check []byte) error { | |||||
| 111 | 113 | ||||
| 112 | // stage makes the batch depend on the scope: the repository key is guarded | 114 | // stage makes the batch depend on the scope: the repository key is guarded | ||
| 113 | // and, for an environment, its record is required at the version read. | 115 | // and, for an environment, its record is required at the version read. | ||
| 116 | + | // | |||
| 117 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates a settings scope and adds repository and environment existence/version preconditions to a storage batch | |||
| 114 | func (s *Settings) stage(ctx context.Context, b *kv.Batch, scope domain.SettingsScope) error { | 118 | func (s *Settings) stage(ctx context.Context, b *kv.Batch, scope domain.SettingsScope) error { | ||
| 115 | if !scope.Valid() { | 119 | if !scope.Valid() { | ||
| 116 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | 120 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | ||
| @@ -203,6 +207,8 @@ func (s *Settings) GetSealedSecret(ctx context.Context, scope domain.SettingsSco | |||||
| 203 | } | 207 | } | ||
| 204 | 208 | ||||
| 205 | // existsIn is exists on a snapshot, so a listing and its check agree. | 209 | // existsIn is exists on a snapshot, so a listing and its check agree. | ||
| 210 | + | // | |||
| 211 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates a settings scope and checks repository and environment keys in the same snapshot as a listing | |||
| 206 | func (s *Settings) existsIn(ctx context.Context, snap *kv.Snapshot, scope domain.SettingsScope) error { | 212 | func (s *Settings) existsIn(ctx context.Context, snap *kv.Snapshot, scope domain.SettingsScope) error { | ||
| 207 | if !scope.Valid() { | 213 | if !scope.Valid() { | ||
| 208 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | 214 | return fmt.Errorf("%w: scope", domain.ErrInvalid) | ||
| @@ -309,8 +315,6 @@ func decodeEnvironment(val []byte) (domain.Environment, error) { | |||||
| 309 | } | 315 | } | ||
| 310 | 316 | ||||
| 311 | // CreateEnvironment implements ports.CISettingsStore. | 317 | // CreateEnvironment implements ports.CISettingsStore. | ||
| 312 | - | // | |||
| 313 | - | //hexcheck:ignore suspicious-business-logic-in-adapter create-if-absent under a version precondition: a storage concern, no policy | |||
| 314 | func (s *Settings) CreateEnvironment(ctx context.Context, repo domain.RepoName, name string, at time.Time) (domain.Environment, error) { | 318 | func (s *Settings) CreateEnvironment(ctx context.Context, repo domain.RepoName, name string, at time.Time) (domain.Environment, error) { | ||
| 315 | key := envKey(repo, name) | 319 | key := envKey(repo, name) | ||
| 316 | for range updateAttempts { | 320 | for range updateAttempts { | ||
| @@ -353,8 +357,6 @@ func (s *Settings) ListEnvironments(ctx context.Context, repo domain.RepoName) ( | |||||
| 353 | } | 357 | } | ||
| 354 | 358 | ||||
| 355 | // DeleteEnvironment implements ports.CISettingsStore. | 359 | // DeleteEnvironment implements ports.CISettingsStore. | ||
| 356 | - | // | |||
| 357 | - | //hexcheck:ignore suspicious-business-logic-in-adapter removes the keys of an environment in one batch: a storage concern, no policy | |||
| 358 | func (s *Settings) DeleteEnvironment(ctx context.Context, repo domain.RepoName, name string) error { | 360 | func (s *Settings) DeleteEnvironment(ctx context.Context, repo domain.RepoName, name string) error { | ||
| 359 | key := envKey(repo, name) | 361 | key := envKey(repo, name) | ||
| 360 | scope := domain.EnvironmentScope(repo, name) | 362 | scope := domain.EnvironmentScope(repo, name) | ||
M internal/adapters/kvstore/issues.go +0 -8
| @@ -84,8 +84,6 @@ func issueKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) [][ | |||
| 84 | 84 | // Create takes the next number of the repository from mrseq/<repo>, the | |
| 85 | 85 | // sequence of the merge requests, and stores the issue under it; see | |
| 86 | 86 | // createNumbered. A missing repository gives domain.ErrNotFound. | |
| 87 | - | // | |
| 88 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |
| 89 | 87 | func (i *Issues) Create(ctx context.Context, issue domain.Issue) (domain.Issue, error) { | |
| 90 | 88 | err := createNumbered(ctx, i.db, i.locks, issue.Repo, func(b *kv.Batch, n int64) error { | |
| 91 | 89 | issue.Number = n | |
| @@ -118,8 +116,6 @@ func (i *Issues) Get(ctx context.Context, repo domain.RepoName, number int64) (d | |||
| 118 | 116 | ||
| 119 | 117 | // List returns a page of the issues of the repository, highest number first. The | |
| 120 | 118 | // page token is the last number of the previous page. | |
| 121 | - | // | |
| 122 | - | //hexcheck:ignore suspicious-business-logic-in-adapter pages through the keys of a prefix: a storage concern, no policy | |
| 123 | 119 | func (i *Issues) List(ctx context.Context, repo domain.RepoName, params ports.ListIssuesParams) (ports.IssuePage, error) { | |
| 124 | 120 | before := int64(0) // 0: from the highest | |
| 125 | 121 | if params.PageToken != "" { | |
| @@ -225,8 +221,6 @@ func (i *Issues) ListOpenAll(ctx context.Context) ([]domain.Issue, error) { | |||
| 225 | 221 | // Update replaces the issue with a version precondition and moves its index key | |
| 226 | 222 | // in the same batch. The repository must exist (see guardRepoKey), so that a | |
| 227 | 223 | // concurrent delete of the repository leaves no index key behind. | |
| 228 | - | // | |
| 229 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |
| 230 | 224 | func (i *Issues) Update(ctx context.Context, issue domain.Issue) error { | |
| 231 | 225 | val, err := encodeIssue(issue) | |
| 232 | 226 | if err != nil { | |
| @@ -330,7 +324,6 @@ func encodeIssue(issue domain.Issue) ([]byte, error) { | |||
| 330 | 324 | }), nil | |
| 331 | 325 | } | |
| 332 | 326 | ||
| 333 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 334 | 327 | func decodeIssue(repo domain.RepoName, item kv.Item) (domain.Issue, error) { | |
| 335 | 328 | var pb storagepb.Issue | |
| 336 | 329 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -373,7 +366,6 @@ func encodeIssueComment(c domain.IssueComment) ([]byte, error) { | |||
| 373 | 366 | }), nil | |
| 374 | 367 | } | |
| 375 | 368 | ||
| 376 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 377 | 369 | func decodeIssueComment(item kv.Item) (domain.IssueComment, error) { | |
| 378 | 370 | var pb storagepb.IssueComment | |
| 379 | 371 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -84,8 +84,6 @@ func issueKeys(ctx context.Context, snap *kv.Snapshot, repo domain.RepoName) [][ | |||||
| 84 | // Create takes the next number of the repository from mrseq/<repo>, the | 84 | // Create takes the next number of the repository from mrseq/<repo>, the | ||
| 85 | // sequence of the merge requests, and stores the issue under it; see | 85 | // sequence of the merge requests, and stores the issue under it; see | ||
| 86 | // createNumbered. A missing repository gives domain.ErrNotFound. | 86 | // createNumbered. A missing repository gives domain.ErrNotFound. | ||
| 87 | - | // | |||
| 88 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |||
| 89 | func (i *Issues) Create(ctx context.Context, issue domain.Issue) (domain.Issue, error) { | 87 | func (i *Issues) Create(ctx context.Context, issue domain.Issue) (domain.Issue, error) { | ||
| 90 | err := createNumbered(ctx, i.db, i.locks, issue.Repo, func(b *kv.Batch, n int64) error { | 88 | err := createNumbered(ctx, i.db, i.locks, issue.Repo, func(b *kv.Batch, n int64) error { | ||
| 91 | issue.Number = n | 89 | issue.Number = n | ||
| @@ -118,8 +116,6 @@ func (i *Issues) Get(ctx context.Context, repo domain.RepoName, number int64) (d | |||||
| 118 | 116 | ||||
| 119 | // List returns a page of the issues of the repository, highest number first. The | 117 | // List returns a page of the issues of the repository, highest number first. The | ||
| 120 | // page token is the last number of the previous page. | 118 | // page token is the last number of the previous page. | ||
| 121 | - | // | |||
| 122 | - | //hexcheck:ignore suspicious-business-logic-in-adapter pages through the keys of a prefix: a storage concern, no policy | |||
| 123 | func (i *Issues) List(ctx context.Context, repo domain.RepoName, params ports.ListIssuesParams) (ports.IssuePage, error) { | 119 | func (i *Issues) List(ctx context.Context, repo domain.RepoName, params ports.ListIssuesParams) (ports.IssuePage, error) { | ||
| 124 | before := int64(0) // 0: from the highest | 120 | before := int64(0) // 0: from the highest | ||
| 125 | if params.PageToken != "" { | 121 | if params.PageToken != "" { | ||
| @@ -225,8 +221,6 @@ func (i *Issues) ListOpenAll(ctx context.Context) ([]domain.Issue, error) { | |||||
| 225 | // Update replaces the issue with a version precondition and moves its index key | 221 | // Update replaces the issue with a version precondition and moves its index key | ||
| 226 | // in the same batch. The repository must exist (see guardRepoKey), so that a | 222 | // in the same batch. The repository must exist (see guardRepoKey), so that a | ||
| 227 | // concurrent delete of the repository leaves no index key behind. | 223 | // concurrent delete of the repository leaves no index key behind. | ||
| 228 | - | // | |||
| 229 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |||
| 230 | func (i *Issues) Update(ctx context.Context, issue domain.Issue) error { | 224 | func (i *Issues) Update(ctx context.Context, issue domain.Issue) error { | ||
| 231 | val, err := encodeIssue(issue) | 225 | val, err := encodeIssue(issue) | ||
| 232 | if err != nil { | 226 | if err != nil { | ||
| @@ -330,7 +324,6 @@ func encodeIssue(issue domain.Issue) ([]byte, error) { | |||||
| 330 | }), nil | 324 | }), nil | ||
| 331 | } | 325 | } | ||
| 332 | 326 | ||||
| 333 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 334 | func decodeIssue(repo domain.RepoName, item kv.Item) (domain.Issue, error) { | 327 | func decodeIssue(repo domain.RepoName, item kv.Item) (domain.Issue, error) { | ||
| 335 | var pb storagepb.Issue | 328 | var pb storagepb.Issue | ||
| 336 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 329 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
| @@ -373,7 +366,6 @@ func encodeIssueComment(c domain.IssueComment) ([]byte, error) { | |||||
| 373 | }), nil | 366 | }), nil | ||
| 374 | } | 367 | } | ||
| 375 | 368 | ||||
| 376 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 377 | func decodeIssueComment(item kv.Item) (domain.IssueComment, error) { | 369 | func decodeIssueComment(item kv.Item) (domain.IssueComment, error) { | ||
| 378 | var pb storagepb.IssueComment | 370 | var pb storagepb.IssueComment | ||
| 379 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 371 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
M internal/adapters/kvstore/issues_pending.go +0 -5
| @@ -94,8 +94,6 @@ func (s *PendingIssues) Get(ctx context.Context, repo domain.RepoName, id domain | |||
| 94 | 94 | // creation time then repository then id. There are at most | |
| 95 | 95 | // domain.MaxPendingIssues of them (a little more under a race), so they are | |
| 96 | 96 | // read and sorted. The page token is the position of the last item returned. | |
| 97 | - | // | |
| 98 | - | //hexcheck:ignore suspicious-business-logic-in-adapter pages through the keys of a prefix: a storage concern, no policy | |
| 99 | 97 | func (s *PendingIssues) List(ctx context.Context, repo domain.RepoName, page ports.ListPendingParams) (ports.PendingIssuePage, error) { | |
| 100 | 98 | prefix := pendingPrefix | |
| 101 | 99 | if !repo.IsZero() { | |
| @@ -216,8 +214,6 @@ func (s *PendingIssues) Count(ctx context.Context) (int, error) { | |||
| 216 | 214 | // Approve numbers the pending issue from mrseq/<repo> (see createNumbered), | |
| 217 | 215 | // writes the open issue and its index key and deletes the pending record, in | |
| 218 | 216 | // one batch that requires the pending record to be unchanged. | |
| 219 | - | // | |
| 220 | - | //hexcheck:ignore suspicious-business-logic-in-adapter only sets the number under a version precondition; the issue itself is built by domain.ApprovedIssue | |
| 221 | 217 | func (s *PendingIssues) Approve(ctx context.Context, repo domain.RepoName, id domain.PendingIssueID, now time.Time) (domain.Issue, error) { | |
| 222 | 218 | var number int64 | |
| 223 | 219 | err := createNumbered(ctx, s.db, s.locks, repo, func(b *kv.Batch, n int64) error { | |
| @@ -291,7 +287,6 @@ func encodePending(p domain.PendingIssue) ([]byte, error) { | |||
| 291 | 287 | }), nil | |
| 292 | 288 | } | |
| 293 | 289 | ||
| 294 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 295 | 290 | func decodePending(repo domain.RepoName, id domain.PendingIssueID, item kv.Item) (domain.PendingIssue, error) { | |
| 296 | 291 | var pb storagepb.PendingIssue | |
| 297 | 292 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -94,8 +94,6 @@ func (s *PendingIssues) Get(ctx context.Context, repo domain.RepoName, id domain | |||||
| 94 | // creation time then repository then id. There are at most | 94 | // creation time then repository then id. There are at most | ||
| 95 | // domain.MaxPendingIssues of them (a little more under a race), so they are | 95 | // domain.MaxPendingIssues of them (a little more under a race), so they are | ||
| 96 | // read and sorted. The page token is the position of the last item returned. | 96 | // read and sorted. The page token is the position of the last item returned. | ||
| 97 | - | // | |||
| 98 | - | //hexcheck:ignore suspicious-business-logic-in-adapter pages through the keys of a prefix: a storage concern, no policy | |||
| 99 | func (s *PendingIssues) List(ctx context.Context, repo domain.RepoName, page ports.ListPendingParams) (ports.PendingIssuePage, error) { | 97 | func (s *PendingIssues) List(ctx context.Context, repo domain.RepoName, page ports.ListPendingParams) (ports.PendingIssuePage, error) { | ||
| 100 | prefix := pendingPrefix | 98 | prefix := pendingPrefix | ||
| 101 | if !repo.IsZero() { | 99 | if !repo.IsZero() { | ||
| @@ -216,8 +214,6 @@ func (s *PendingIssues) Count(ctx context.Context) (int, error) { | |||||
| 216 | // Approve numbers the pending issue from mrseq/<repo> (see createNumbered), | 214 | // Approve numbers the pending issue from mrseq/<repo> (see createNumbered), | ||
| 217 | // writes the open issue and its index key and deletes the pending record, in | 215 | // writes the open issue and its index key and deletes the pending record, in | ||
| 218 | // one batch that requires the pending record to be unchanged. | 216 | // one batch that requires the pending record to be unchanged. | ||
| 219 | - | // | |||
| 220 | - | //hexcheck:ignore suspicious-business-logic-in-adapter only sets the number under a version precondition; the issue itself is built by domain.ApprovedIssue | |||
| 221 | func (s *PendingIssues) Approve(ctx context.Context, repo domain.RepoName, id domain.PendingIssueID, now time.Time) (domain.Issue, error) { | 217 | func (s *PendingIssues) Approve(ctx context.Context, repo domain.RepoName, id domain.PendingIssueID, now time.Time) (domain.Issue, error) { | ||
| 222 | var number int64 | 218 | var number int64 | ||
| 223 | err := createNumbered(ctx, s.db, s.locks, repo, func(b *kv.Batch, n int64) error { | 219 | err := createNumbered(ctx, s.db, s.locks, repo, func(b *kv.Batch, n int64) error { | ||
| @@ -291,7 +287,6 @@ func encodePending(p domain.PendingIssue) ([]byte, error) { | |||||
| 291 | }), nil | 287 | }), nil | ||
| 292 | } | 288 | } | ||
| 293 | 289 | ||||
| 294 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 295 | func decodePending(repo domain.RepoName, id domain.PendingIssueID, item kv.Item) (domain.PendingIssue, error) { | 290 | func decodePending(repo domain.RepoName, id domain.PendingIssueID, item kv.Item) (domain.PendingIssue, error) { | ||
| 296 | var pb storagepb.PendingIssue | 291 | var pb storagepb.PendingIssue | ||
| 297 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 292 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
M internal/adapters/kvstore/mergerequests.go +3 -9
| @@ -96,6 +96,8 @@ func indexKey(prefix string, repo domain.RepoName, branch string, n int64) []byt | |||
| 96 | 96 | // when old is not known, as for a new request or a comment: the keys of mr are | |
| 97 | 97 | // then put or deleted, whatever they were). Deleting a key that is not there is | |
| 98 | 98 | // not an error. | |
| 99 | + | // | |
| 100 | + | //hexcheck:ignore suspicious-business-logic-in-adapter maintains source and target indexes to match the stored merge request open state and branch names | |
| 99 | 101 | func indexOpen(b *kv.Batch, old *domain.MergeRequest, mr domain.MergeRequest) { | |
| 100 | 102 | if old != nil && old.IsOpen() { | |
| 101 | 103 | if !mr.IsOpen() || old.Source != mr.Source { | |
| @@ -204,8 +206,6 @@ func (m *MergeRequests) guardRepo(ctx context.Context, b *kv.Batch, repo domain. | |||
| 204 | 206 | // rewrites it (see guardRepo), so that a repository deleted meanwhile is not | |
| 205 | 207 | // left with a stray merge request (a push recording pushed_at makes it retry). A missing repository gives | |
| 206 | 208 | // domain.ErrNotFound. | |
| 207 | - | // | |
| 208 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |
| 209 | 209 | func (m *MergeRequests) Create(ctx context.Context, mr domain.MergeRequest) (domain.MergeRequest, error) { | |
| 210 | 210 | err := createNumbered(ctx, m.db, m.locks, mr.Repo, func(b *kv.Batch, n int64) error { | |
| 211 | 211 | mr.Number = n | |
| @@ -451,7 +451,7 @@ func (m *MergeRequests) CountOpen(ctx context.Context, repo domain.RepoName) (in | |||
| 451 | 451 | ||
| 452 | 452 | // Update replaces the merge request with a version precondition. | |
| 453 | 453 | // | |
| 454 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |
| 454 | + | //hexcheck:ignore suspicious-business-logic-in-adapter replaces a versioned record and maintains open-request indexes and the derived mergeability record | |
| 455 | 455 | func (m *MergeRequests) Update(ctx context.Context, mr domain.MergeRequest) error { | |
| 456 | 456 | val, err := encodeMergeRequest(mr) | |
| 457 | 457 | if err != nil { | |
| @@ -564,8 +564,6 @@ func (m *MergeRequests) GetRead(ctx context.Context, repo domain.RepoName, numbe | |||
| 564 | 564 | ||
| 565 | 565 | // SetRead writes mrread/<repo>/<number>. The repository must exist (see | |
| 566 | 566 | // guardRepo): domain.ErrNotFound otherwise. | |
| 567 | - | // | |
| 568 | - | //hexcheck:ignore suspicious-business-logic-in-adapter retries a write that lost a race with the repository key: a storage concern, no policy | |
| 569 | 567 | func (m *MergeRequests) SetRead(ctx context.Context, repo domain.RepoName, number int64, head domain.ObjectID) error { | |
| 570 | 568 | if head.IsZero() { | |
| 571 | 569 | return fmt.Errorf("%w: empty read position", domain.ErrInvalidObjectID) | |
| @@ -748,7 +746,6 @@ func encodeMergeRequest(mr domain.MergeRequest) ([]byte, error) { | |||
| 748 | 746 | }), nil | |
| 749 | 747 | } | |
| 750 | 748 | ||
| 751 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 752 | 749 | func decodeMergeRequest(repo domain.RepoName, item kv.Item) (domain.MergeRequest, error) { | |
| 753 | 750 | var pb storagepb.MergeRequest | |
| 754 | 751 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -815,7 +812,6 @@ func encodeComment(c domain.Comment) ([]byte, error) { | |||
| 815 | 812 | }), nil | |
| 816 | 813 | } | |
| 817 | 814 | ||
| 818 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 819 | 815 | func decodeComment(item kv.Item) (domain.Comment, error) { | |
| 820 | 816 | var pb storagepb.Comment | |
| 821 | 817 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | |
| @@ -931,8 +927,6 @@ func encodeSettings(s domain.RepoSettings) (*storagepb.RepoSettings, error) { | |||
| 931 | 927 | ||
| 932 | 928 | // decodeSettings returns the defaults for a repository stored before merge | |
| 933 | 929 | // requests existed, and for settings left with no mode that this build knows. | |
| 934 | - | // | |
| 935 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding with the documented defaults | |
| 936 | 930 | func decodeSettings(pb *storagepb.RepoSettings) domain.RepoSettings { | |
| 937 | 931 | if pb == nil { | |
| 938 | 932 | return domain.DefaultRepoSettings() | |
| @@ -96,6 +96,8 @@ func indexKey(prefix string, repo domain.RepoName, branch string, n int64) []byt | |||||
| 96 | // when old is not known, as for a new request or a comment: the keys of mr are | 96 | // when old is not known, as for a new request or a comment: the keys of mr are | ||
| 97 | // then put or deleted, whatever they were). Deleting a key that is not there is | 97 | // then put or deleted, whatever they were). Deleting a key that is not there is | ||
| 98 | // not an error. | 98 | // not an error. | ||
| 99 | + | // | |||
| 100 | + | //hexcheck:ignore suspicious-business-logic-in-adapter maintains source and target indexes to match the stored merge request open state and branch names | |||
| 99 | func indexOpen(b *kv.Batch, old *domain.MergeRequest, mr domain.MergeRequest) { | 101 | func indexOpen(b *kv.Batch, old *domain.MergeRequest, mr domain.MergeRequest) { | ||
| 100 | if old != nil && old.IsOpen() { | 102 | if old != nil && old.IsOpen() { | ||
| 101 | if !mr.IsOpen() || old.Source != mr.Source { | 103 | if !mr.IsOpen() || old.Source != mr.Source { | ||
| @@ -204,8 +206,6 @@ func (m *MergeRequests) guardRepo(ctx context.Context, b *kv.Batch, repo domain. | |||||
| 204 | // rewrites it (see guardRepo), so that a repository deleted meanwhile is not | 206 | // rewrites it (see guardRepo), so that a repository deleted meanwhile is not | ||
| 205 | // left with a stray merge request (a push recording pushed_at makes it retry). A missing repository gives | 207 | // left with a stray merge request (a push recording pushed_at makes it retry). A missing repository gives | ||
| 206 | // domain.ErrNotFound. | 208 | // domain.ErrNotFound. | ||
| 207 | - | // | |||
| 208 | - | //hexcheck:ignore suspicious-business-logic-in-adapter takes the next number under a version precondition: a storage concern, no policy | |||
| 209 | func (m *MergeRequests) Create(ctx context.Context, mr domain.MergeRequest) (domain.MergeRequest, error) { | 209 | func (m *MergeRequests) Create(ctx context.Context, mr domain.MergeRequest) (domain.MergeRequest, error) { | ||
| 210 | err := createNumbered(ctx, m.db, m.locks, mr.Repo, func(b *kv.Batch, n int64) error { | 210 | err := createNumbered(ctx, m.db, m.locks, mr.Repo, func(b *kv.Batch, n int64) error { | ||
| 211 | mr.Number = n | 211 | mr.Number = n | ||
| @@ -451,7 +451,7 @@ func (m *MergeRequests) CountOpen(ctx context.Context, repo domain.RepoName) (in | |||||
| 451 | 451 | ||||
| 452 | // Update replaces the merge request with a version precondition. | 452 | // Update replaces the merge request with a version precondition. | ||
| 453 | // | 453 | // | ||
| 454 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | 454 | + | //hexcheck:ignore suspicious-business-logic-in-adapter replaces a versioned record and maintains open-request indexes and the derived mergeability record |
| 455 | func (m *MergeRequests) Update(ctx context.Context, mr domain.MergeRequest) error { | 455 | func (m *MergeRequests) Update(ctx context.Context, mr domain.MergeRequest) error { | ||
| 456 | val, err := encodeMergeRequest(mr) | 456 | val, err := encodeMergeRequest(mr) | ||
| 457 | if err != nil { | 457 | if err != nil { | ||
| @@ -564,8 +564,6 @@ func (m *MergeRequests) GetRead(ctx context.Context, repo domain.RepoName, numbe | |||||
| 564 | 564 | ||||
| 565 | // SetRead writes mrread/<repo>/<number>. The repository must exist (see | 565 | // SetRead writes mrread/<repo>/<number>. The repository must exist (see | ||
| 566 | // guardRepo): domain.ErrNotFound otherwise. | 566 | // guardRepo): domain.ErrNotFound otherwise. | ||
| 567 | - | // | |||
| 568 | - | //hexcheck:ignore suspicious-business-logic-in-adapter retries a write that lost a race with the repository key: a storage concern, no policy | |||
| 569 | func (m *MergeRequests) SetRead(ctx context.Context, repo domain.RepoName, number int64, head domain.ObjectID) error { | 567 | func (m *MergeRequests) SetRead(ctx context.Context, repo domain.RepoName, number int64, head domain.ObjectID) error { | ||
| 570 | if head.IsZero() { | 568 | if head.IsZero() { | ||
| 571 | return fmt.Errorf("%w: empty read position", domain.ErrInvalidObjectID) | 569 | return fmt.Errorf("%w: empty read position", domain.ErrInvalidObjectID) | ||
| @@ -748,7 +746,6 @@ func encodeMergeRequest(mr domain.MergeRequest) ([]byte, error) { | |||||
| 748 | }), nil | 746 | }), nil | ||
| 749 | } | 747 | } | ||
| 750 | 748 | ||||
| 751 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 752 | func decodeMergeRequest(repo domain.RepoName, item kv.Item) (domain.MergeRequest, error) { | 749 | func decodeMergeRequest(repo domain.RepoName, item kv.Item) (domain.MergeRequest, error) { | ||
| 753 | var pb storagepb.MergeRequest | 750 | var pb storagepb.MergeRequest | ||
| 754 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 751 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
| @@ -815,7 +812,6 @@ func encodeComment(c domain.Comment) ([]byte, error) { | |||||
| 815 | }), nil | 812 | }), nil | ||
| 816 | } | 813 | } | ||
| 817 | 814 | ||||
| 818 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 819 | func decodeComment(item kv.Item) (domain.Comment, error) { | 815 | func decodeComment(item kv.Item) (domain.Comment, error) { | ||
| 820 | var pb storagepb.Comment | 816 | var pb storagepb.Comment | ||
| 821 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | 817 | if err := proto.Unmarshal(item.Value, &pb); err != nil { | ||
| @@ -931,8 +927,6 @@ func encodeSettings(s domain.RepoSettings) (*storagepb.RepoSettings, error) { | |||||
| 931 | 927 | ||||
| 932 | // decodeSettings returns the defaults for a repository stored before merge | 928 | // decodeSettings returns the defaults for a repository stored before merge | ||
| 933 | // requests existed, and for settings left with no mode that this build knows. | 929 | // requests existed, and for settings left with no mode that this build knows. | ||
| 934 | - | // | |||
| 935 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding with the documented defaults | |||
| 936 | func decodeSettings(pb *storagepb.RepoSettings) domain.RepoSettings { | 930 | func decodeSettings(pb *storagepb.RepoSettings) domain.RepoSettings { | ||
| 937 | if pb == nil { | 931 | if pb == nil { | ||
| 938 | return domain.DefaultRepoSettings() | 932 | return domain.DefaultRepoSettings() | ||
M internal/adapters/kvstore/passkeys.go +0 -2
| @@ -134,8 +134,6 @@ func (s *Passkeys) Create(ctx context.Context, p domain.Passkey) error { | |||
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | 136 | // Update replaces a stored passkey, or returns domain.ErrNotFound. | |
| 137 | - | // | |
| 138 | - | //hexcheck:ignore suspicious-business-logic-in-adapter version-checked replace, not a policy | |
| 139 | 137 | func (s *Passkeys) Update(ctx context.Context, p domain.Passkey) error { | |
| 140 | 138 | val, err := encodePasskey(p) | |
| 141 | 139 | if err != nil { | |
| @@ -134,8 +134,6 @@ func (s *Passkeys) Create(ctx context.Context, p domain.Passkey) error { | |||||
| 134 | } | 134 | } | ||
| 135 | 135 | ||||
| 136 | // Update replaces a stored passkey, or returns domain.ErrNotFound. | 136 | // Update replaces a stored passkey, or returns domain.ErrNotFound. | ||
| 137 | - | // | |||
| 138 | - | //hexcheck:ignore suspicious-business-logic-in-adapter version-checked replace, not a policy | |||
| 139 | func (s *Passkeys) Update(ctx context.Context, p domain.Passkey) error { | 137 | func (s *Passkeys) Update(ctx context.Context, p domain.Passkey) error { | ||
| 140 | val, err := encodePasskey(p) | 138 | val, err := encodePasskey(p) | ||
| 141 | if err != nil { | 139 | if err != nil { | ||
M internal/adapters/kvstore/repos.go +0 -4
| @@ -67,8 +67,6 @@ func (s *Store) List(ctx context.Context) ([]domain.Repo, error) { | |||
| 67 | 67 | const repoMutationTries = 8 | |
| 68 | 68 | ||
| 69 | 69 | // Mutate applies a retry-safe mutation under the version it read. | |
| 70 | - | // | |
| 71 | - | //hexcheck:ignore suspicious-business-logic-in-adapter optimistic concurrency is a storage concern | |
| 72 | 70 | func (s *Store) Mutate(ctx context.Context, name domain.RepoName, fn func(*domain.Repo) (bool, error)) (domain.Repo, error) { | |
| 73 | 71 | key := repoKey(name) | |
| 74 | 72 | for range repoMutationTries { | |
| @@ -158,8 +156,6 @@ const deleteTries = 32 | |||
| 158 | 156 | // got in after the listing makes the batch fail and the keys are listed again, | |
| 159 | 157 | // and a write after the batch finds no repository: no key outlives the | |
| 160 | 158 | // repository to attach itself to a repository created again. | |
| 161 | - | // | |
| 162 | - | //hexcheck:ignore suspicious-business-logic-in-adapter chunked delete under a version precondition: a storage concern, no policy | |
| 163 | 159 | func (s *Store) Delete(ctx context.Context, name domain.RepoName) error { | |
| 164 | 160 | for range deleteTries { | |
| 165 | 161 | snap := s.db.Snapshot(ctx) | |
| @@ -67,8 +67,6 @@ func (s *Store) List(ctx context.Context) ([]domain.Repo, error) { | |||||
| 67 | const repoMutationTries = 8 | 67 | const repoMutationTries = 8 | ||
| 68 | 68 | ||||
| 69 | // Mutate applies a retry-safe mutation under the version it read. | 69 | // Mutate applies a retry-safe mutation under the version it read. | ||
| 70 | - | // | |||
| 71 | - | //hexcheck:ignore suspicious-business-logic-in-adapter optimistic concurrency is a storage concern | |||
| 72 | func (s *Store) Mutate(ctx context.Context, name domain.RepoName, fn func(*domain.Repo) (bool, error)) (domain.Repo, error) { | 70 | func (s *Store) Mutate(ctx context.Context, name domain.RepoName, fn func(*domain.Repo) (bool, error)) (domain.Repo, error) { | ||
| 73 | key := repoKey(name) | 71 | key := repoKey(name) | ||
| 74 | for range repoMutationTries { | 72 | for range repoMutationTries { | ||
| @@ -158,8 +156,6 @@ const deleteTries = 32 | |||||
| 158 | // got in after the listing makes the batch fail and the keys are listed again, | 156 | // got in after the listing makes the batch fail and the keys are listed again, | ||
| 159 | // and a write after the batch finds no repository: no key outlives the | 157 | // and a write after the batch finds no repository: no key outlives the | ||
| 160 | // repository to attach itself to a repository created again. | 158 | // repository to attach itself to a repository created again. | ||
| 161 | - | // | |||
| 162 | - | //hexcheck:ignore suspicious-business-logic-in-adapter chunked delete under a version precondition: a storage concern, no policy | |||
| 163 | func (s *Store) Delete(ctx context.Context, name domain.RepoName) error { | 159 | func (s *Store) Delete(ctx context.Context, name domain.RepoName) error { | ||
| 164 | for range deleteTries { | 160 | for range deleteTries { | ||
| 165 | snap := s.db.Snapshot(ctx) | 161 | snap := s.db.Snapshot(ctx) | ||
M internal/adapters/kvstore/store.go +0 -2
| @@ -186,8 +186,6 @@ var preIssueScopes = []domain.Scope{ | |||
| 186 | 186 | // for, so it gets each of them if missing (this is no escalation). Every other | |
| 187 | 187 | // token is left as it is. The batch requires each token to be at the version it | |
| 188 | 188 | // was read at. | |
| 189 | - | // | |
| 190 | - | //hexcheck:ignore suspicious-business-logic-in-adapter one-time storage upgrade of the stored tokens: a storage concern, no policy | |
| 191 | 189 | func (s *Store) upgradeTokens(ctx context.Context, b *kv.Batch) error { | |
| 192 | 190 | for key, item := range s.db.Snapshot(ctx).Prefix(ctx, []byte(tokenPrefix)) { | |
| 193 | 191 | pb := &storagepb.Token{} | |
| @@ -186,8 +186,6 @@ var preIssueScopes = []domain.Scope{ | |||||
| 186 | // for, so it gets each of them if missing (this is no escalation). Every other | 186 | // for, so it gets each of them if missing (this is no escalation). Every other | ||
| 187 | // token is left as it is. The batch requires each token to be at the version it | 187 | // token is left as it is. The batch requires each token to be at the version it | ||
| 188 | // was read at. | 188 | // was read at. | ||
| 189 | - | // | |||
| 190 | - | //hexcheck:ignore suspicious-business-logic-in-adapter one-time storage upgrade of the stored tokens: a storage concern, no policy | |||
| 191 | func (s *Store) upgradeTokens(ctx context.Context, b *kv.Batch) error { | 189 | func (s *Store) upgradeTokens(ctx context.Context, b *kv.Batch) error { | ||
| 192 | for key, item := range s.db.Snapshot(ctx).Prefix(ctx, []byte(tokenPrefix)) { | 190 | for key, item := range s.db.Snapshot(ctx).Prefix(ctx, []byte(tokenPrefix)) { | ||
| 193 | pb := &storagepb.Token{} | 191 | pb := &storagepb.Token{} | ||
M internal/adapters/kvstore/tokens.go +0 -6
| @@ -153,8 +153,6 @@ func (s *Tokens) Revoke(ctx context.Context, id string) error { | |||
| 153 | 153 | ||
| 154 | 154 | // Touch sets last_used_at when the given time is later than the stored one, | |
| 155 | 155 | // so that racing writers never move it back. | |
| 156 | - | // | |
| 157 | - | //hexcheck:ignore suspicious-business-logic-in-adapter monotonic write guard, not a policy | |
| 158 | 156 | func (s *Tokens) Touch(ctx context.Context, id string, at time.Time) error { | |
| 159 | 157 | if !validTokenID(id) { | |
| 160 | 158 | return domain.ErrNotFound | |
| @@ -194,8 +192,6 @@ func (s *Tokens) Touch(ctx context.Context, id string, at time.Time) error { | |||
| 194 | 192 | // encodeToken refuses what the use case already refused (scopes, branch | |
| 195 | 193 | // prefixes): a malformed prefix must never reach the store, where it would | |
| 196 | 194 | // limit a token wrongly or not at all. | |
| 197 | - | // | |
| 198 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema encoding: it re-checks the syntax the use case enforced, it decides no policy | |
| 199 | 195 | func encodeToken(t domain.Token) ([]byte, error) { | |
| 200 | 196 | if !validTokenID(t.ID) { | |
| 201 | 197 | return nil, fmt.Errorf("%w: invalid id %q", domain.ErrInvalidToken, t.ID) | |
| @@ -237,8 +233,6 @@ func encodeToken(t domain.Token) ([]byte, error) { | |||
| 237 | 233 | ||
| 238 | 234 | // decodeToken drops scopes it does not know (written by a newer ermite): a | |
| 239 | 235 | // token never gains rights by being read by an older build. | |
| 240 | - | // | |
| 241 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |
| 242 | 236 | func decodeToken(val []byte) (domain.Token, error) { | |
| 243 | 237 | var pb storagepb.Token | |
| 244 | 238 | if err := proto.Unmarshal(val, &pb); err != nil { | |
| @@ -153,8 +153,6 @@ func (s *Tokens) Revoke(ctx context.Context, id string) error { | |||||
| 153 | 153 | ||||
| 154 | // Touch sets last_used_at when the given time is later than the stored one, | 154 | // Touch sets last_used_at when the given time is later than the stored one, | ||
| 155 | // so that racing writers never move it back. | 155 | // so that racing writers never move it back. | ||
| 156 | - | // | |||
| 157 | - | //hexcheck:ignore suspicious-business-logic-in-adapter monotonic write guard, not a policy | |||
| 158 | func (s *Tokens) Touch(ctx context.Context, id string, at time.Time) error { | 156 | func (s *Tokens) Touch(ctx context.Context, id string, at time.Time) error { | ||
| 159 | if !validTokenID(id) { | 157 | if !validTokenID(id) { | ||
| 160 | return domain.ErrNotFound | 158 | return domain.ErrNotFound | ||
| @@ -194,8 +192,6 @@ func (s *Tokens) Touch(ctx context.Context, id string, at time.Time) error { | |||||
| 194 | // encodeToken refuses what the use case already refused (scopes, branch | 192 | // encodeToken refuses what the use case already refused (scopes, branch | ||
| 195 | // prefixes): a malformed prefix must never reach the store, where it would | 193 | // prefixes): a malformed prefix must never reach the store, where it would | ||
| 196 | // limit a token wrongly or not at all. | 194 | // limit a token wrongly or not at all. | ||
| 197 | - | // | |||
| 198 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema encoding: it re-checks the syntax the use case enforced, it decides no policy | |||
| 199 | func encodeToken(t domain.Token) ([]byte, error) { | 195 | func encodeToken(t domain.Token) ([]byte, error) { | ||
| 200 | if !validTokenID(t.ID) { | 196 | if !validTokenID(t.ID) { | ||
| 201 | return nil, fmt.Errorf("%w: invalid id %q", domain.ErrInvalidToken, t.ID) | 197 | return nil, fmt.Errorf("%w: invalid id %q", domain.ErrInvalidToken, t.ID) | ||
| @@ -237,8 +233,6 @@ func encodeToken(t domain.Token) ([]byte, error) { | |||||
| 237 | 233 | ||||
| 238 | // decodeToken drops scopes it does not know (written by a newer ermite): a | 234 | // decodeToken drops scopes it does not know (written by a newer ermite): a | ||
| 239 | // token never gains rights by being read by an older build. | 235 | // token never gains rights by being read by an older build. | ||
| 240 | - | // | |||
| 241 | - | //hexcheck:ignore suspicious-business-logic-in-adapter schema decoding, not a policy | |||
| 242 | func decodeToken(val []byte) (domain.Token, error) { | 236 | func decodeToken(val []byte) (domain.Token, error) { | ||
| 243 | var pb storagepb.Token | 237 | var pb storagepb.Token | ||
| 244 | if err := proto.Unmarshal(val, &pb); err != nil { | 238 | if err := proto.Unmarshal(val, &pb); err != nil { | ||
M internal/adapters/rpc/git.go +0 -1
| @@ -187,7 +187,6 @@ func (s *gitService) GetCommit(ctx context.Context, req *connect.Request[pb.GetC | |||
| 187 | 187 | return connect.NewResponse(commitDetailToPB(detail)), nil | |
| 188 | 188 | } | |
| 189 | 189 | ||
| 190 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |
| 191 | 190 | func (s *gitService) ResolveRevision(ctx context.Context, req *connect.Request[pb.ResolveRevisionRequest]) (*connect.Response[pb.ResolveRevisionResponse], error) { | |
| 192 | 191 | name, rev, err := target(req.Msg.GetRepo(), req.Msg.GetRevision()) | |
| 193 | 192 | if err != nil { | |
| @@ -187,7 +187,6 @@ func (s *gitService) GetCommit(ctx context.Context, req *connect.Request[pb.GetC | |||||
| 187 | return connect.NewResponse(commitDetailToPB(detail)), nil | 187 | return connect.NewResponse(commitDetailToPB(detail)), nil | ||
| 188 | } | 188 | } | ||
| 189 | 189 | ||||
| 190 | - | //hexcheck:ignore suspicious-business-logic-in-adapter port method name only | |||
| 191 | func (s *gitService) ResolveRevision(ctx context.Context, req *connect.Request[pb.ResolveRevisionRequest]) (*connect.Response[pb.ResolveRevisionResponse], error) { | 190 | func (s *gitService) ResolveRevision(ctx context.Context, req *connect.Request[pb.ResolveRevisionRequest]) (*connect.Response[pb.ResolveRevisionResponse], error) { | ||
| 192 | name, rev, err := target(req.Msg.GetRepo(), req.Msg.GetRevision()) | 191 | name, rev, err := target(req.Msg.GetRepo(), req.Msg.GetRevision()) | ||
| 193 | if err != nil { | 192 | if err != nil { | ||
M internal/adapters/rpc/mergerequest.go +0 -2
| @@ -212,8 +212,6 @@ func commentID(s string) int64 { | |||
| 212 | 212 | } | |
| 213 | 213 | ||
| 214 | 214 | // headID parses a commit id of a request; the empty string is the zero id. | |
| 215 | - | // | |
| 216 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses a request field into the domain id and names the field in the error; no rule is decided here | |
| 217 | 215 | func headID(s string) (domain.ObjectID, error) { | |
| 218 | 216 | if s == "" { | |
| 219 | 217 | return domain.ObjectID{}, nil | |
| @@ -212,8 +212,6 @@ func commentID(s string) int64 { | |||||
| 212 | } | 212 | } | ||
| 213 | 213 | ||||
| 214 | // headID parses a commit id of a request; the empty string is the zero id. | 214 | // headID parses a commit id of a request; the empty string is the zero id. | ||
| 215 | - | // | |||
| 216 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses a request field into the domain id and names the field in the error; no rule is decided here | |||
| 217 | func headID(s string) (domain.ObjectID, error) { | 215 | func headID(s string) (domain.ObjectID, error) { | ||
| 218 | if s == "" { | 216 | if s == "" { | ||
| 219 | return domain.ObjectID{}, nil | 217 | return domain.ObjectID{}, nil | ||
M internal/adapters/rpc/repo.go +0 -2
| @@ -83,8 +83,6 @@ func (s *repoService) UpdateRepo(ctx context.Context, req *connect.Request[pb.Up | |||
| 83 | 83 | // "settings.allowed_merge_modes" and "settings.failing_checks_block", and | |
| 84 | 84 | // nothing else; the optional issues field stands outside the mask, and alone | |
| 85 | 85 | // it is a valid update. | |
| 86 | - | // | |
| 87 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the field mask of the contract to the optional fields of the use case; no rule is decided here | |
| 88 | 86 | func updateParams(msg *pb.UpdateRepoRequest) (ports.UpdateRepoParams, error) { | |
| 89 | 87 | var params ports.UpdateRepoParams | |
| 90 | 88 | paths := msg.GetUpdateMask().GetPaths() | |
| @@ -83,8 +83,6 @@ func (s *repoService) UpdateRepo(ctx context.Context, req *connect.Request[pb.Up | |||||
| 83 | // "settings.allowed_merge_modes" and "settings.failing_checks_block", and | 83 | // "settings.allowed_merge_modes" and "settings.failing_checks_block", and | ||
| 84 | // nothing else; the optional issues field stands outside the mask, and alone | 84 | // nothing else; the optional issues field stands outside the mask, and alone | ||
| 85 | // it is a valid update. | 85 | // it is a valid update. | ||
| 86 | - | // | |||
| 87 | - | //hexcheck:ignore suspicious-business-logic-in-adapter maps the field mask of the contract to the optional fields of the use case; no rule is decided here | |||
| 88 | func updateParams(msg *pb.UpdateRepoRequest) (ports.UpdateRepoParams, error) { | 86 | func updateParams(msg *pb.UpdateRepoRequest) (ports.UpdateRepoParams, error) { | ||
| 89 | var params ports.UpdateRepoParams | 87 | var params ports.UpdateRepoParams | ||
| 90 | paths := msg.GetUpdateMask().GetPaths() | 88 | paths := msg.GetUpdateMask().GetPaths() | ||
M internal/adapters/rpc/server.go +2 -0
| @@ -42,6 +42,8 @@ func (s *serverService) GetSigningKey(context.Context, *connect.Request[pb.GetSi | |||
| 42 | 42 | ||
| 43 | 43 | // RotateOIDCKey replaces the key that signs the ID tokens of CI jobs. Only the | |
| 44 | 44 | // owner may; failed_precondition when the server issues no ID tokens. | |
| 45 | + | // | |
| 46 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy restricting disabled-OIDC rotation errors to owners; pending move to domain/usecase | |
| 45 | 47 | func (s *serverService) RotateOIDCKey(ctx context.Context, _ *connect.Request[pb.RotateOIDCKeyRequest]) (*connect.Response[pb.RotateOIDCKeyResponse], error) { | |
| 46 | 48 | p := caller(ctx) | |
| 47 | 49 | if s.oidc == nil { | |
| @@ -42,6 +42,8 @@ func (s *serverService) GetSigningKey(context.Context, *connect.Request[pb.GetSi | |||||
| 42 | 42 | ||||
| 43 | // RotateOIDCKey replaces the key that signs the ID tokens of CI jobs. Only the | 43 | // RotateOIDCKey replaces the key that signs the ID tokens of CI jobs. Only the | ||
| 44 | // owner may; failed_precondition when the server issues no ID tokens. | 44 | // owner may; failed_precondition when the server issues no ID tokens. | ||
| 45 | + | // | |||
| 46 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy restricting disabled-OIDC rotation errors to owners; pending move to domain/usecase | |||
| 45 | func (s *serverService) RotateOIDCKey(ctx context.Context, _ *connect.Request[pb.RotateOIDCKeyRequest]) (*connect.Response[pb.RotateOIDCKeyResponse], error) { | 47 | func (s *serverService) RotateOIDCKey(ctx context.Context, _ *connect.Request[pb.RotateOIDCKeyRequest]) (*connect.Response[pb.RotateOIDCKeyResponse], error) { | ||
| 46 | p := caller(ctx) | 48 | p := caller(ctx) | ||
| 47 | if s.oidc == nil { | 49 | if s.oidc == nil { | ||
M internal/adapters/sigverify/gpg.go +0 -2
| @@ -41,8 +41,6 @@ var _ ports.SignatureVerifier = GPG{} | |||
| 41 | 41 | ||
| 42 | 42 | // Verify implements ports.SignatureVerifier. signedAt is ignored: see the time | |
| 43 | 43 | // policy of GPG. | |
| 44 | - | // | |
| 45 | - | //hexcheck:ignore suspicious-business-logic-in-adapter this is the OpenPGP protocol check the port delegates to the adapter; the trust and email rules stay in domain | |
| 46 | 44 | func (GPG) Verify(payload, signature []byte, committerEmail string, _ int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | |
| 47 | 45 | v = domain.CommitVerification{Format: domain.FormatGPG, Status: domain.StatusBadSignature} | |
| 48 | 46 | defer func() { // a parser bug must not take the server down | |
| @@ -41,8 +41,6 @@ var _ ports.SignatureVerifier = GPG{} | |||||
| 41 | 41 | ||||
| 42 | // Verify implements ports.SignatureVerifier. signedAt is ignored: see the time | 42 | // Verify implements ports.SignatureVerifier. signedAt is ignored: see the time | ||
| 43 | // policy of GPG. | 43 | // policy of GPG. | ||
| 44 | - | // | |||
| 45 | - | //hexcheck:ignore suspicious-business-logic-in-adapter this is the OpenPGP protocol check the port delegates to the adapter; the trust and email rules stay in domain | |||
| 46 | func (GPG) Verify(payload, signature []byte, committerEmail string, _ int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | 44 | func (GPG) Verify(payload, signature []byte, committerEmail string, _ int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | ||
| 47 | v = domain.CommitVerification{Format: domain.FormatGPG, Status: domain.StatusBadSignature} | 45 | v = domain.CommitVerification{Format: domain.FormatGPG, Status: domain.StatusBadSignature} | ||
| 48 | defer func() { // a parser bug must not take the server down | 46 | defer func() { // a parser bug must not take the server down | ||
M internal/adapters/sigverify/ssh.go +0 -2
| @@ -49,8 +49,6 @@ type sshSigBlob struct { | |||
| 49 | 49 | } | |
| 50 | 50 | ||
| 51 | 51 | // Verify implements ports.SignatureVerifier. | |
| 52 | - | // | |
| 53 | - | //hexcheck:ignore suspicious-business-logic-in-adapter this is the SSHSIG protocol check the port delegates to the adapter; the trust and email rules stay in domain | |
| 54 | 52 | func (SSH) Verify(payload, signature []byte, committerEmail string, signedAt int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | |
| 55 | 53 | v = domain.CommitVerification{Format: domain.FormatSSH, Status: domain.StatusBadSignature} | |
| 56 | 54 | defer func() { // a parser bug must not take the server down | |
| @@ -49,8 +49,6 @@ type sshSigBlob struct { | |||||
| 49 | } | 49 | } | ||
| 50 | 50 | ||||
| 51 | // Verify implements ports.SignatureVerifier. | 51 | // Verify implements ports.SignatureVerifier. | ||
| 52 | - | // | |||
| 53 | - | //hexcheck:ignore suspicious-business-logic-in-adapter this is the SSHSIG protocol check the port delegates to the adapter; the trust and email rules stay in domain | |||
| 54 | func (SSH) Verify(payload, signature []byte, committerEmail string, signedAt int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | 52 | func (SSH) Verify(payload, signature []byte, committerEmail string, signedAt int64, keys []domain.TrustedKey) (v domain.CommitVerification) { | ||
| 55 | v = domain.CommitVerification{Format: domain.FormatSSH, Status: domain.StatusBadSignature} | 53 | v = domain.CommitVerification{Format: domain.FormatSSH, Status: domain.StatusBadSignature} | ||
| 56 | defer func() { // a parser bug must not take the server down | 54 | defer func() { // a parser bug must not take the server down | ||
M internal/adapters/sigverify/verifier.go +0 -2
| @@ -42,8 +42,6 @@ func (Verifier) Verify(payload, signature []byte, committerEmail string, signedA | |||
| 42 | 42 | // trusted completes the verification of a signature whose cryptography is | |
| 43 | 43 | // valid and whose key is trusted: verified when the key may sign for the | |
| 44 | 44 | // committer email, email_mismatch otherwise. | |
| 45 | - | // | |
| 46 | - | //hexcheck:ignore suspicious-business-logic-in-adapter the email rule is domain.TrustedKey.TrustsEmail; this only maps it to the port's status | |
| 47 | 45 | func trusted(v domain.CommitVerification, key domain.TrustedKey, committerEmail string) domain.CommitVerification { | |
| 48 | 46 | v.KeyID, v.KeyTitle = key.ID, key.Title | |
| 49 | 47 | if key.TrustsEmail(committerEmail) { | |
| @@ -42,8 +42,6 @@ func (Verifier) Verify(payload, signature []byte, committerEmail string, signedA | |||||
| 42 | // trusted completes the verification of a signature whose cryptography is | 42 | // trusted completes the verification of a signature whose cryptography is | ||
| 43 | // valid and whose key is trusted: verified when the key may sign for the | 43 | // valid and whose key is trusted: verified when the key may sign for the | ||
| 44 | // committer email, email_mismatch otherwise. | 44 | // committer email, email_mismatch otherwise. | ||
| 45 | - | // | |||
| 46 | - | //hexcheck:ignore suspicious-business-logic-in-adapter the email rule is domain.TrustedKey.TrustsEmail; this only maps it to the port's status | |||
| 47 | func trusted(v domain.CommitVerification, key domain.TrustedKey, committerEmail string) domain.CommitVerification { | 45 | func trusted(v domain.CommitVerification, key domain.TrustedKey, committerEmail string) domain.CommitVerification { | ||
| 48 | v.KeyID, v.KeyTitle = key.ID, key.Title | 46 | v.KeyID, v.KeyTitle = key.ID, key.Title | ||
| 49 | if key.TrustsEmail(committerEmail) { | 47 | if key.TrustsEmail(committerEmail) { | ||
M internal/adapters/web/actions_artifacts.go +0 -4
| @@ -53,8 +53,6 @@ type ArtifactsView struct { | |||
| 53 | 53 | // runArtifacts is the artifacts section of a run, nil when there is nothing to | |
| 54 | 54 | // show: no artifacts on this server, a visitor who cannot list them, no | |
| 55 | 55 | // artifact, or a failed read, which is logged; the run page never fails for it. | |
| 56 | - | // | |
| 57 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the artifacts section from the use case results; which errors hide it is presentation, no rule is decided here | |
| 58 | 56 | func (s *Server) runArtifacts(ctx context.Context, repo domain.RepoName, p RunPage) *ArtifactsView { | |
| 59 | 57 | if s.cfg.Artifacts == nil || !SignedIn(ctx) { | |
| 60 | 58 | return nil | |
| @@ -112,8 +110,6 @@ func parseArtifactPath(r *http.Request) (int64, error) { | |||
| 112 | 110 | // is never served: a zip is application/zip, anything else | |
| 113 | 111 | // application/octet-stream, and the answer is sandboxed and not sniffed, so | |
| 114 | 112 | // that nothing uploaded by a job can run in the origin of the forge. | |
| 115 | - | // | |
| 116 | - | //hexcheck:ignore suspicious-business-logic-in-adapter streams what the use case sends; the headers are about the response, no rule is decided here | |
| 117 | 113 | func (s *Server) artifactDownload(w http.ResponseWriter, r *http.Request) { | |
| 118 | 114 | ctx, cancel := context.WithTimeout(r.Context(), artifactTimeout) | |
| 119 | 115 | defer cancel() | |
| @@ -53,8 +53,6 @@ type ArtifactsView struct { | |||||
| 53 | // runArtifacts is the artifacts section of a run, nil when there is nothing to | 53 | // runArtifacts is the artifacts section of a run, nil when there is nothing to | ||
| 54 | // show: no artifacts on this server, a visitor who cannot list them, no | 54 | // show: no artifacts on this server, a visitor who cannot list them, no | ||
| 55 | // artifact, or a failed read, which is logged; the run page never fails for it. | 55 | // artifact, or a failed read, which is logged; the run page never fails for it. | ||
| 56 | - | // | |||
| 57 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the artifacts section from the use case results; which errors hide it is presentation, no rule is decided here | |||
| 58 | func (s *Server) runArtifacts(ctx context.Context, repo domain.RepoName, p RunPage) *ArtifactsView { | 56 | func (s *Server) runArtifacts(ctx context.Context, repo domain.RepoName, p RunPage) *ArtifactsView { | ||
| 59 | if s.cfg.Artifacts == nil || !SignedIn(ctx) { | 57 | if s.cfg.Artifacts == nil || !SignedIn(ctx) { | ||
| 60 | return nil | 58 | return nil | ||
| @@ -112,8 +110,6 @@ func parseArtifactPath(r *http.Request) (int64, error) { | |||||
| 112 | // is never served: a zip is application/zip, anything else | 110 | // is never served: a zip is application/zip, anything else | ||
| 113 | // application/octet-stream, and the answer is sandboxed and not sniffed, so | 111 | // application/octet-stream, and the answer is sandboxed and not sniffed, so | ||
| 114 | // that nothing uploaded by a job can run in the origin of the forge. | 112 | // that nothing uploaded by a job can run in the origin of the forge. | ||
| 115 | - | // | |||
| 116 | - | //hexcheck:ignore suspicious-business-logic-in-adapter streams what the use case sends; the headers are about the response, no rule is decided here | |||
| 117 | func (s *Server) artifactDownload(w http.ResponseWriter, r *http.Request) { | 113 | func (s *Server) artifactDownload(w http.ResponseWriter, r *http.Request) { | ||
| 118 | ctx, cancel := context.WithTimeout(r.Context(), artifactTimeout) | 114 | ctx, cancel := context.WithTimeout(r.Context(), artifactTimeout) | ||
| 119 | defer cancel() | 115 | defer cancel() | ||
M internal/adapters/web/browse.go +0 -2
| @@ -71,8 +71,6 @@ func (s *Server) openBlobAt(ctx context.Context, repo domain.RepoName, rev, path | |||
| 71 | 71 | } | |
| 72 | 72 | ||
| 73 | 73 | // resolveRevision resolves rev to the commit it designates. | |
| 74 | - | // | |
| 75 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses the URL text and calls the use case; no rule is decided here | |
| 76 | 74 | func (s *Server) resolveRevision(ctx context.Context, repo domain.RepoName, rev string) (domain.ResolvedRevision, error) { | |
| 77 | 75 | r, err := domain.ParseRevision(rev) | |
| 78 | 76 | if err != nil { | |
| @@ -71,8 +71,6 @@ func (s *Server) openBlobAt(ctx context.Context, repo domain.RepoName, rev, path | |||||
| 71 | } | 71 | } | ||
| 72 | 72 | ||||
| 73 | // resolveRevision resolves rev to the commit it designates. | 73 | // resolveRevision resolves rev to the commit it designates. | ||
| 74 | - | // | |||
| 75 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses the URL text and calls the use case; no rule is decided here | |||
| 76 | func (s *Server) resolveRevision(ctx context.Context, repo domain.RepoName, rev string) (domain.ResolvedRevision, error) { | 74 | func (s *Server) resolveRevision(ctx context.Context, repo domain.RepoName, rev string) (domain.ResolvedRevision, error) { | ||
| 77 | r, err := domain.ParseRevision(rev) | 75 | r, err := domain.ParseRevision(rev) | ||
| 78 | if err != nil { | 76 | if err != nil { | ||
M internal/adapters/web/checks.go +2 -0
| @@ -53,6 +53,8 @@ func (s *Server) checksFor(ctx context.Context, repo domain.RepoName, sha string | |||
| 53 | 53 | } | |
| 54 | 54 | ||
| 55 | 55 | // checksSummary reduces checks to the mark a list shows next to a commit. | |
| 56 | + | // | |
| 57 | + | //hexcheck:ignore suspicious-business-logic-in-adapter renders domain check outcomes as a commit-list mark, passed count, label and actions link | |
| 56 | 58 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | |
| 57 | 59 | if len(checks) == 0 { | |
| 58 | 60 | return ChecksSummary{} | |
| @@ -53,6 +53,8 @@ func (s *Server) checksFor(ctx context.Context, repo domain.RepoName, sha string | |||||
| 53 | } | 53 | } | ||
| 54 | 54 | ||||
| 55 | // checksSummary reduces checks to the mark a list shows next to a commit. | 55 | // checksSummary reduces checks to the mark a list shows next to a commit. | ||
| 56 | + | // | |||
| 57 | + | //hexcheck:ignore suspicious-business-logic-in-adapter renders domain check outcomes as a commit-list mark, passed count, label and actions link | |||
| 56 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | 58 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | ||
| 57 | if len(checks) == 0 { | 59 | if len(checks) == 0 { | ||
| 58 | return ChecksSummary{} | 60 | return ChecksSummary{} | ||
M internal/adapters/web/commit.go +0 -2
| @@ -96,8 +96,6 @@ func diffLines(files []DiffFile) (lines int, invisible bool) { | |||
| 96 | 96 | ||
| 97 | 97 | // commit shows a commit: its message, its totals, the changed files and the | |
| 98 | 98 | // diff against the first parent. ?view=split selects the split layout. | |
| 99 | - | // | |
| 100 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the commit page from the use case results; no rule is decided here | |
| 101 | 99 | func (s *Server) commit(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 102 | 100 | sha := r.PathValue("sha") | |
| 103 | 101 | if !isCommitID(sha) { | |
| @@ -96,8 +96,6 @@ func diffLines(files []DiffFile) (lines int, invisible bool) { | |||||
| 96 | 96 | ||||
| 97 | // commit shows a commit: its message, its totals, the changed files and the | 97 | // commit shows a commit: its message, its totals, the changed files and the | ||
| 98 | // diff against the first parent. ?view=split selects the split layout. | 98 | // diff against the first parent. ?view=split selects the split layout. | ||
| 99 | - | // | |||
| 100 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the commit page from the use case results; no rule is decided here | |||
| 101 | func (s *Server) commit(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 99 | func (s *Server) commit(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 102 | sha := r.PathValue("sha") | 100 | sha := r.PathValue("sha") | ||
| 103 | if !isCommitID(sha) { | 101 | if !isCommitID(sha) { | ||
M internal/adapters/web/compare.go +1 -3
| @@ -27,8 +27,6 @@ const compareDepth = maxComparePages * pageSize | |||
| 27 | 27 | // own diff is then the whole change). Otherwise it lists the commits, which | |
| 28 | 28 | // link to their own diffs, and says the whole diff comes with the merge | |
| 29 | 29 | // request. | |
| 30 | - | // | |
| 31 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the compare page from the use case results; the merge rules are the use case's | |
| 32 | 30 | func (s *Server) compare(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 33 | 31 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | |
| 34 | 32 | if err != nil { | |
| @@ -144,7 +142,7 @@ func (s *Server) compare(ctx context.Context, r *http.Request) (templ.Component, | |||
| 144 | 142 | // meets the target. behind is true when the target has commits the source | |
| 145 | 143 | // lacks (the tip of the target is not an ancestor of the source). | |
| 146 | 144 | // | |
| 147 | - | //hexcheck:ignore suspicious-business-logic-in-adapter walks the history pages the use case returns to find where the branch left its target; the page needs it, the forge decides nothing | |
| 145 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule inferring ahead/behind from bounded history walks; pending move to domain/usecase | |
| 148 | 146 | func (s *Server) commitsAhead(ctx context.Context, repo domain.RepoName, srcTip, tgtTip string) (ahead []domain.Commit, exact, behind bool, err error) { | |
| 149 | 147 | if srcTip == tgtTip { | |
| 150 | 148 | return nil, true, false, nil | |
| @@ -27,8 +27,6 @@ const compareDepth = maxComparePages * pageSize | |||||
| 27 | // own diff is then the whole change). Otherwise it lists the commits, which | 27 | // own diff is then the whole change). Otherwise it lists the commits, which | ||
| 28 | // link to their own diffs, and says the whole diff comes with the merge | 28 | // link to their own diffs, and says the whole diff comes with the merge | ||
| 29 | // request. | 29 | // request. | ||
| 30 | - | // | |||
| 31 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the compare page from the use case results; the merge rules are the use case's | |||
| 32 | func (s *Server) compare(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 30 | func (s *Server) compare(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 33 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | 31 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | ||
| 34 | if err != nil { | 32 | if err != nil { | ||
| @@ -144,7 +142,7 @@ func (s *Server) compare(ctx context.Context, r *http.Request) (templ.Component, | |||||
| 144 | // meets the target. behind is true when the target has commits the source | 142 | // meets the target. behind is true when the target has commits the source | ||
| 145 | // lacks (the tip of the target is not an ancestor of the source). | 143 | // lacks (the tip of the target is not an ancestor of the source). | ||
| 146 | // | 144 | // | ||
| 147 | - | //hexcheck:ignore suspicious-business-logic-in-adapter walks the history pages the use case returns to find where the branch left its target; the page needs it, the forge decides nothing | 145 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule inferring ahead/behind from bounded history walks; pending move to domain/usecase |
| 148 | func (s *Server) commitsAhead(ctx context.Context, repo domain.RepoName, srcTip, tgtTip string) (ahead []domain.Commit, exact, behind bool, err error) { | 146 | func (s *Server) commitsAhead(ctx context.Context, repo domain.RepoName, srcTip, tgtTip string) (ahead []domain.Commit, exact, behind bool, err error) { | ||
| 149 | if srcTip == tgtTip { | 147 | if srcTip == tgtTip { | ||
| 150 | return nil, true, false, nil | 148 | return nil, true, false, nil | ||
M internal/adapters/web/context.go +1 -1
| @@ -30,7 +30,7 @@ type ContextRows struct { | |||
| 30 | 30 | // the numbers of the first hidden line on each side, which move together (the | |
| 31 | 31 | // lines are unchanged); n the number of lines, 0 for the rest of the file. | |
| 32 | 32 | // | |
| 33 | - | //hexcheck:ignore suspicious-business-logic-in-adapter cuts a file the use case opened into rows of the diff; no rule is decided here | |
| 33 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates diff-context HTTP parameters, rejects binary or oversized files, and caps rendered context rows | |
| 34 | 34 | func (s *Server) diffContext(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 35 | 35 | sha := r.PathValue("sha") | |
| 36 | 36 | if !isFullID(sha) { | |
| @@ -30,7 +30,7 @@ type ContextRows struct { | |||||
| 30 | // the numbers of the first hidden line on each side, which move together (the | 30 | // the numbers of the first hidden line on each side, which move together (the | ||
| 31 | // lines are unchanged); n the number of lines, 0 for the rest of the file. | 31 | // lines are unchanged); n the number of lines, 0 for the rest of the file. | ||
| 32 | // | 32 | // | ||
| 33 | - | //hexcheck:ignore suspicious-business-logic-in-adapter cuts a file the use case opened into rows of the diff; no rule is decided here | 33 | + | //hexcheck:ignore suspicious-business-logic-in-adapter validates diff-context HTTP parameters, rejects binary or oversized files, and caps rendered context rows |
| 34 | func (s *Server) diffContext(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 34 | func (s *Server) diffContext(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 35 | sha := r.PathValue("sha") | 35 | sha := r.PathValue("sha") | ||
| 36 | if !isFullID(sha) { | 36 | if !isFullID(sha) { | ||
M internal/adapters/web/diff_highlight.go +0 -2
| @@ -370,8 +370,6 @@ func computeFile(ctx context.Context, lx chroma.Lexer, hunks []domain.Hunk) (d * | |||
| 370 | 370 | ||
| 371 | 371 | // applyFile puts the colours on the lines of a file; false when the data is | |
| 372 | 372 | // not the one of this file (another number of lines), nothing is changed. | |
| 373 | - | // | |
| 374 | - | //hexcheck:ignore suspicious-business-logic-in-adapter puts coloured runs on the lines of a diff for the page; no rule is decided here | |
| 375 | 373 | func applyFile(d *hlData, f *DiffFile, hunks []domain.Hunk) bool { | |
| 376 | 374 | n := 0 | |
| 377 | 375 | for _, h := range hunks { | |
| @@ -370,8 +370,6 @@ func computeFile(ctx context.Context, lx chroma.Lexer, hunks []domain.Hunk) (d * | |||||
| 370 | 370 | ||||
| 371 | // applyFile puts the colours on the lines of a file; false when the data is | 371 | // applyFile puts the colours on the lines of a file; false when the data is | ||
| 372 | // not the one of this file (another number of lines), nothing is changed. | 372 | // not the one of this file (another number of lines), nothing is changed. | ||
| 373 | - | // | |||
| 374 | - | //hexcheck:ignore suspicious-business-logic-in-adapter puts coloured runs on the lines of a diff for the page; no rule is decided here | |||
| 375 | func applyFile(d *hlData, f *DiffFile, hunks []domain.Hunk) bool { | 373 | func applyFile(d *hlData, f *DiffFile, hunks []domain.Hunk) bool { | ||
| 376 | n := 0 | 374 | n := 0 | ||
| 377 | for _, h := range hunks { | 375 | for _, h := range hunks { | ||
M internal/adapters/web/events.go +2 -0
| @@ -342,6 +342,8 @@ func (s *Server) canSee(ctx context.Context, rawName string) error { | |||
| 342 | 342 | ||
| 343 | 343 | // issuesOn is domain.ErrNotFound unless the repository has issues on and | |
| 344 | 344 | // s.cfg.Issues is set: the same answer as for a repository the visitor cannot see. | |
| 345 | + | // | |
| 346 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy hiding issue streams when issues are disabled; pending move to domain/usecase | |
| 345 | 347 | func (s *Server) issuesOn(ctx context.Context, rawName string) error { | |
| 346 | 348 | if s.cfg.Issues == nil { | |
| 347 | 349 | return domain.ErrNotFound | |
| @@ -342,6 +342,8 @@ func (s *Server) canSee(ctx context.Context, rawName string) error { | |||||
| 342 | 342 | ||||
| 343 | // issuesOn is domain.ErrNotFound unless the repository has issues on and | 343 | // issuesOn is domain.ErrNotFound unless the repository has issues on and | ||
| 344 | // s.cfg.Issues is set: the same answer as for a repository the visitor cannot see. | 344 | // s.cfg.Issues is set: the same answer as for a repository the visitor cannot see. | ||
| 345 | + | // | |||
| 346 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy hiding issue streams when issues are disabled; pending move to domain/usecase | |||
| 345 | func (s *Server) issuesOn(ctx context.Context, rawName string) error { | 347 | func (s *Server) issuesOn(ctx context.Context, rawName string) error { | ||
| 346 | if s.cfg.Issues == nil { | 348 | if s.cfg.Issues == nil { | ||
| 347 | return domain.ErrNotFound | 349 | return domain.ErrNotFound | ||
M internal/adapters/web/fragments.go +1 -1
| @@ -356,7 +356,7 @@ func (f *fanout) lead(key fanKey, e *fanEntry, build func() ([]fragment, error)) | |||
| 356 | 356 | // banner tells the commits page how many commits its branch got since the | |
| 357 | 357 | // head it lists. | |
| 358 | 358 | // | |
| 359 | - | //hexcheck:ignore suspicious-business-logic-in-adapter counts the commits of a page for the banner text; display only | |
| 359 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule inferring new commit counts and branch rewrites from one history page; pending move to domain/usecase | |
| 360 | 360 | func (l *liveStream) banner(ctx context.Context, p domain.PushEvent) ([]fragment, error) { | |
| 361 | 361 | if l.ref == "" || !isFullID(l.head) { | |
| 362 | 362 | return nil, nil | |
| @@ -356,7 +356,7 @@ func (f *fanout) lead(key fanKey, e *fanEntry, build func() ([]fragment, error)) | |||||
| 356 | // banner tells the commits page how many commits its branch got since the | 356 | // banner tells the commits page how many commits its branch got since the | ||
| 357 | // head it lists. | 357 | // head it lists. | ||
| 358 | // | 358 | // | ||
| 359 | - | //hexcheck:ignore suspicious-business-logic-in-adapter counts the commits of a page for the banner text; display only | 359 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule inferring new commit counts and branch rewrites from one history page; pending move to domain/usecase |
| 360 | func (l *liveStream) banner(ctx context.Context, p domain.PushEvent) ([]fragment, error) { | 360 | func (l *liveStream) banner(ctx context.Context, p domain.PushEvent) ([]fragment, error) { | ||
| 361 | if l.ref == "" || !isFullID(l.head) { | 361 | if l.ref == "" || !isFullID(l.head) { | ||
| 362 | return nil, nil | 362 | return nil, nil | ||
M internal/adapters/web/issues.go +0 -2
| @@ -216,8 +216,6 @@ func (s *Server) issueNew(ctx context.Context, r *http.Request) (templ.Component | |||
| 216 | 216 | } | |
| 217 | 217 | ||
| 218 | 218 | // issueShow shows an issue with its comments. | |
| 219 | - | // | |
| 220 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the issue page from the use case results; no rule is decided here | |
| 221 | 219 | func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 222 | 220 | n, err := mrNumber(r) | |
| 223 | 221 | if err != nil { | |
| @@ -216,8 +216,6 @@ func (s *Server) issueNew(ctx context.Context, r *http.Request) (templ.Component | |||||
| 216 | } | 216 | } | ||
| 217 | 217 | ||||
| 218 | // issueShow shows an issue with its comments. | 218 | // issueShow shows an issue with its comments. | ||
| 219 | - | // | |||
| 220 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the issue page from the use case results; no rule is decided here | |||
| 221 | func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 219 | func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 222 | n, err := mrNumber(r) | 220 | n, err := mrNumber(r) | ||
| 223 | if err != nil { | 221 | if err != nil { | ||
M internal/adapters/web/issues_form.go +2 -0
| @@ -245,6 +245,8 @@ func (s *Server) formAgain(ctx context.Context, w http.ResponseWriter, r *http.R | |||
| 245 | 245 | } | |
| 246 | 246 | ||
| 247 | 247 | // issueSubmittedPage is GET /<repo>/issues/submitted. | |
| 248 | + | // | |
| 249 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy exposing the submission receipt only for public issues; pending move to domain/usecase | |
| 248 | 250 | func (s *Server) issueSubmittedPage(w http.ResponseWriter, r *http.Request) { | |
| 249 | 251 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | |
| 250 | 252 | defer cancel() | |
| @@ -245,6 +245,8 @@ func (s *Server) formAgain(ctx context.Context, w http.ResponseWriter, r *http.R | |||||
| 245 | } | 245 | } | ||
| 246 | 246 | ||||
| 247 | // issueSubmittedPage is GET /<repo>/issues/submitted. | 247 | // issueSubmittedPage is GET /<repo>/issues/submitted. | ||
| 248 | + | // | |||
| 249 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business policy exposing the submission receipt only for public issues; pending move to domain/usecase | |||
| 248 | func (s *Server) issueSubmittedPage(w http.ResponseWriter, r *http.Request) { | 250 | func (s *Server) issueSubmittedPage(w http.ResponseWriter, r *http.Request) { | ||
| 249 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | 251 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | ||
| 250 | defer cancel() | 252 | defer cancel() | ||
M internal/adapters/web/issues_post.go +0 -1
| @@ -67,7 +67,6 @@ func (s *Server) issueReopen(ctx context.Context, r *http.Request) (string, stri | |||
| 67 | 67 | return s.issueTransition(ctx, r, s.cfg.Issues.Reopen) | |
| 68 | 68 | } | |
| 69 | 69 | ||
| 70 | - | //hexcheck:ignore suspicious-business-logic-in-adapter closes or reopens through the use case that owns the transition; the form only picks which | |
| 71 | 70 | func (s *Server) issueTransition(ctx context.Context, r *http.Request, do func(context.Context, domain.Principal, domain.RepoName, int64) (domain.Issue, error)) (string, string, error) { | |
| 72 | 71 | repo := r.PathValue("repo") | |
| 73 | 72 | n, err := number(r) | |
| @@ -67,7 +67,6 @@ func (s *Server) issueReopen(ctx context.Context, r *http.Request) (string, stri | |||||
| 67 | return s.issueTransition(ctx, r, s.cfg.Issues.Reopen) | 67 | return s.issueTransition(ctx, r, s.cfg.Issues.Reopen) | ||
| 68 | } | 68 | } | ||
| 69 | 69 | ||||
| 70 | - | //hexcheck:ignore suspicious-business-logic-in-adapter closes or reopens through the use case that owns the transition; the form only picks which | |||
| 71 | func (s *Server) issueTransition(ctx context.Context, r *http.Request, do func(context.Context, domain.Principal, domain.RepoName, int64) (domain.Issue, error)) (string, string, error) { | 70 | func (s *Server) issueTransition(ctx context.Context, r *http.Request, do func(context.Context, domain.Principal, domain.RepoName, int64) (domain.Issue, error)) (string, string, error) { | ||
| 72 | repo := r.PathValue("repo") | 71 | repo := r.PathValue("repo") | ||
| 73 | n, err := number(r) | 72 | n, err := number(r) | ||
M internal/adapters/web/mr.go +1 -1
| @@ -546,7 +546,7 @@ func (s *Server) mrSince(ctx context.Context, r *http.Request) (templ.Component, | |||
| 546 | 546 | return s.mrPage(ctx, r, true) | |
| 547 | 547 | } | |
| 548 | 548 | ||
| 549 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the merge request page from the use case results; no rule is decided here | |
| 549 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rules for owner-only read positions and identifying unread commits; pending move to domain/usecase | |
| 550 | 550 | func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ.Component, int, error) { | |
| 551 | 551 | n, err := mrNumber(r) | |
| 552 | 552 | if err != nil { | |
| @@ -546,7 +546,7 @@ func (s *Server) mrSince(ctx context.Context, r *http.Request) (templ.Component, | |||||
| 546 | return s.mrPage(ctx, r, true) | 546 | return s.mrPage(ctx, r, true) | ||
| 547 | } | 547 | } | ||
| 548 | 548 | ||||
| 549 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the merge request page from the use case results; no rule is decided here | 549 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rules for owner-only read positions and identifying unread commits; pending move to domain/usecase |
| 550 | func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ.Component, int, error) { | 550 | func (s *Server) mrPage(ctx context.Context, r *http.Request, since bool) (templ.Component, int, error) { | ||
| 551 | n, err := mrNumber(r) | 551 | n, err := mrNumber(r) | ||
| 552 | if err != nil { | 552 | if err != nil { | ||
M internal/adapters/web/mr_files.go +0 -2
| @@ -157,8 +157,6 @@ func splitPath(p string) (name, dir string) { | |||
| 157 | 157 | // the files of a window with their hunks and their comments, for a | |
| 158 | 158 | // placeholder of the page. A base or a head that is not the one of the diff | |
| 159 | 159 | // any more answers 409: the page says to reload. | |
| 160 | - | // | |
| 161 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds a window of the merge request page from the use case results; no rule is decided here | |
| 162 | 160 | func (s *Server) mrFiles(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 163 | 161 | n, err := mrNumber(r) | |
| 164 | 162 | if err != nil { | |
| @@ -157,8 +157,6 @@ func splitPath(p string) (name, dir string) { | |||||
| 157 | // the files of a window with their hunks and their comments, for a | 157 | // the files of a window with their hunks and their comments, for a | ||
| 158 | // placeholder of the page. A base or a head that is not the one of the diff | 158 | // placeholder of the page. A base or a head that is not the one of the diff | ||
| 159 | // any more answers 409: the page says to reload. | 159 | // any more answers 409: the page says to reload. | ||
| 160 | - | // | |||
| 161 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds a window of the merge request page from the use case results; no rule is decided here | |||
| 162 | func (s *Server) mrFiles(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 160 | func (s *Server) mrFiles(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 163 | n, err := mrNumber(r) | 161 | n, err := mrNumber(r) | ||
| 164 | if err != nil { | 162 | if err != nil { | ||
M internal/adapters/web/mr_post.go +0 -2
| @@ -295,8 +295,6 @@ func commentID(s string) int64 { | |||
| 295 | 295 | } | |
| 296 | 296 | ||
| 297 | 297 | // headID parses a commit id of a form; the empty string is the zero id. | |
| 298 | - | // | |
| 299 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses a form field into the domain id and names the field in the error; no rule is decided here | |
| 300 | 298 | func headID(s string) (domain.ObjectID, error) { | |
| 301 | 299 | if s == "" { | |
| 302 | 300 | return domain.ObjectID{}, nil | |
| @@ -295,8 +295,6 @@ func commentID(s string) int64 { | |||||
| 295 | } | 295 | } | ||
| 296 | 296 | ||||
| 297 | // headID parses a commit id of a form; the empty string is the zero id. | 297 | // headID parses a commit id of a form; the empty string is the zero id. | ||
| 298 | - | // | |||
| 299 | - | //hexcheck:ignore suspicious-business-logic-in-adapter parses a form field into the domain id and names the field in the error; no rule is decided here | |||
| 300 | func headID(s string) (domain.ObjectID, error) { | 298 | func headID(s string) (domain.ObjectID, error) { | ||
| 301 | if s == "" { | 299 | if s == "" { | ||
| 302 | return domain.ObjectID{}, nil | 300 | return domain.ObjectID{}, nil | ||
M internal/adapters/web/paths.go +0 -2
| @@ -33,8 +33,6 @@ type pathList struct { | |||
| 33 | 33 | // an ETag that makes it a 304 (answered before the list is loaded, so it never | |
| 34 | 34 | // waits for a build); the owner's copy is private and never stored. The ETag | |
| 35 | 35 | // differs for the gzip and the plain variant. | |
| 36 | - | // | |
| 37 | - | //hexcheck:ignore suspicious-business-logic-in-adapter serves a cached list after the use case authorized it; the headers are about the response, no rule is decided here | |
| 38 | 36 | func (s *Server) paths(w http.ResponseWriter, r *http.Request) { | |
| 39 | 37 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | |
| 40 | 38 | defer cancel() | |
| @@ -33,8 +33,6 @@ type pathList struct { | |||||
| 33 | // an ETag that makes it a 304 (answered before the list is loaded, so it never | 33 | // an ETag that makes it a 304 (answered before the list is loaded, so it never | ||
| 34 | // waits for a build); the owner's copy is private and never stored. The ETag | 34 | // waits for a build); the owner's copy is private and never stored. The ETag | ||
| 35 | // differs for the gzip and the plain variant. | 35 | // differs for the gzip and the plain variant. | ||
| 36 | - | // | |||
| 37 | - | //hexcheck:ignore suspicious-business-logic-in-adapter serves a cached list after the use case authorized it; the headers are about the response, no rule is decided here | |||
| 38 | func (s *Server) paths(w http.ResponseWriter, r *http.Request) { | 36 | func (s *Server) paths(w http.ResponseWriter, r *http.Request) { | ||
| 39 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | 37 | ctx, cancel := context.WithTimeout(r.Context(), requestTimeout) | ||
| 40 | defer cancel() | 38 | defer cancel() | ||
M internal/adapters/web/raw.go +0 -2
| @@ -31,8 +31,6 @@ const rawCSP = "default-src 'none'; sandbox" | |||
| 31 | 31 | // image types (by their bytes, never SVG) as images, and anything else as an | |
| 32 | 32 | // attachment of unknown type. A file is never served as HTML or SVG, so what | |
| 33 | 33 | // a repository holds cannot run in the origin of the forge. | |
| 34 | - | // | |
| 35 | - | //hexcheck:ignore suspicious-business-logic-in-adapter streams a file the use case opened; the headers are about the response, no rule is decided here | |
| 36 | 34 | func (s *Server) raw(w http.ResponseWriter, r *http.Request) { | |
| 37 | 35 | ctx, cancel := context.WithTimeout(r.Context(), rawTimeout) | |
| 38 | 36 | defer cancel() | |
| @@ -31,8 +31,6 @@ const rawCSP = "default-src 'none'; sandbox" | |||||
| 31 | // image types (by their bytes, never SVG) as images, and anything else as an | 31 | // image types (by their bytes, never SVG) as images, and anything else as an | ||
| 32 | // attachment of unknown type. A file is never served as HTML or SVG, so what | 32 | // attachment of unknown type. A file is never served as HTML or SVG, so what | ||
| 33 | // a repository holds cannot run in the origin of the forge. | 33 | // a repository holds cannot run in the origin of the forge. | ||
| 34 | - | // | |||
| 35 | - | //hexcheck:ignore suspicious-business-logic-in-adapter streams a file the use case opened; the headers are about the response, no rule is decided here | |||
| 36 | func (s *Server) raw(w http.ResponseWriter, r *http.Request) { | 34 | func (s *Server) raw(w http.ResponseWriter, r *http.Request) { | ||
| 37 | ctx, cancel := context.WithTimeout(r.Context(), rawTimeout) | 35 | ctx, cancel := context.WithTimeout(r.Context(), rawTimeout) | ||
| 38 | defer cancel() | 36 | defer cancel() | ||
M internal/adapters/web/refs.go +0 -4
| @@ -15,8 +15,6 @@ import ( | |||
| 15 | 15 | // that is the short name of a branch or tag wins. A branch wins over a tag of | |
| 16 | 16 | // the same name. rest has no leading slash and is "" when the path is the ref | |
| 17 | 17 | // alone. ok is false when no ref matches; the caller may then try a commit id. | |
| 18 | - | // | |
| 19 | - | //hexcheck:ignore suspicious-business-logic-in-adapter finds the ref a URL path starts with; URL routing, no rule is decided here | |
| 20 | 18 | func resolveRef(refs []domain.Ref, p string) (ref domain.Ref, rest string, ok bool) { | |
| 21 | 19 | names := refsByName(refs) | |
| 22 | 20 | p = strings.Trim(p, "/") | |
| @@ -97,8 +95,6 @@ func (t target) commitID() string { | |||
| 97 | 95 | // resolveCommit sets the full id of a target named by an abbreviated commit id, | |
| 98 | 96 | // with one ResolveRevision. The page renders without it (it only lacks the file | |
| 99 | 97 | // finder), so a failure is not one. | |
| 100 | - | // | |
| 101 | - | //hexcheck:ignore suspicious-business-logic-in-adapter learns the full id of the commit a URL names for the finder links; no rule is decided here | |
| 102 | 98 | func (s *Server) resolveCommit(ctx context.Context, repo domain.RepoName, t *target) { | |
| 103 | 99 | if !t.detached || isFullID(t.rev) { | |
| 104 | 100 | return | |
| @@ -15,8 +15,6 @@ import ( | |||||
| 15 | // that is the short name of a branch or tag wins. A branch wins over a tag of | 15 | // that is the short name of a branch or tag wins. A branch wins over a tag of | ||
| 16 | // the same name. rest has no leading slash and is "" when the path is the ref | 16 | // the same name. rest has no leading slash and is "" when the path is the ref | ||
| 17 | // alone. ok is false when no ref matches; the caller may then try a commit id. | 17 | // alone. ok is false when no ref matches; the caller may then try a commit id. | ||
| 18 | - | // | |||
| 19 | - | //hexcheck:ignore suspicious-business-logic-in-adapter finds the ref a URL path starts with; URL routing, no rule is decided here | |||
| 20 | func resolveRef(refs []domain.Ref, p string) (ref domain.Ref, rest string, ok bool) { | 18 | func resolveRef(refs []domain.Ref, p string) (ref domain.Ref, rest string, ok bool) { | ||
| 21 | names := refsByName(refs) | 19 | names := refsByName(refs) | ||
| 22 | p = strings.Trim(p, "/") | 20 | p = strings.Trim(p, "/") | ||
| @@ -97,8 +95,6 @@ func (t target) commitID() string { | |||||
| 97 | // resolveCommit sets the full id of a target named by an abbreviated commit id, | 95 | // resolveCommit sets the full id of a target named by an abbreviated commit id, | ||
| 98 | // with one ResolveRevision. The page renders without it (it only lacks the file | 96 | // with one ResolveRevision. The page renders without it (it only lacks the file | ||
| 99 | // finder), so a failure is not one. | 97 | // finder), so a failure is not one. | ||
| 100 | - | // | |||
| 101 | - | //hexcheck:ignore suspicious-business-logic-in-adapter learns the full id of the commit a URL names for the finder links; no rule is decided here | |||
| 102 | func (s *Server) resolveCommit(ctx context.Context, repo domain.RepoName, t *target) { | 98 | func (s *Server) resolveCommit(ctx context.Context, repo domain.RepoName, t *target) { | ||
| 103 | if !t.detached || isFullID(t.rev) { | 99 | if !t.detached || isFullID(t.rev) { | ||
| 104 | return | 100 | return | ||
M internal/adapters/web/repo.go +1 -1
| @@ -45,7 +45,7 @@ func (s *Server) repoView(ctx context.Context, name domain.RepoName) (ports.Repo | |||
| 45 | 45 | // repoRecord reads the repository record only, without Git: its name, | |
| 46 | 46 | // visibility and settings (the defaults when it has none). | |
| 47 | 47 | // | |
| 48 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the repository from the use case; filling in the default settings for display decides no rule | |
| 48 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule replacing zero repository settings with defaults; pending move to domain/usecase | |
| 49 | 49 | func (s *Server) repoRecord(ctx context.Context, name domain.RepoName) (domain.Repo, error) { | |
| 50 | 50 | repo, err := s.cfg.Repos.Get(ctx, principal(ctx), name) | |
| 51 | 51 | if err != nil { | |
| @@ -45,7 +45,7 @@ func (s *Server) repoView(ctx context.Context, name domain.RepoName) (ports.Repo | |||||
| 45 | // repoRecord reads the repository record only, without Git: its name, | 45 | // repoRecord reads the repository record only, without Git: its name, | ||
| 46 | // visibility and settings (the defaults when it has none). | 46 | // visibility and settings (the defaults when it has none). | ||
| 47 | // | 47 | // | ||
| 48 | - | //hexcheck:ignore suspicious-business-logic-in-adapter reads the repository from the use case; filling in the default settings for display decides no rule | 48 | + | //hexcheck:ignore suspicious-business-logic-in-adapter business rule replacing zero repository settings with defaults; pending move to domain/usecase |
| 49 | func (s *Server) repoRecord(ctx context.Context, name domain.RepoName) (domain.Repo, error) { | 49 | func (s *Server) repoRecord(ctx context.Context, name domain.RepoName) (domain.Repo, error) { | ||
| 50 | repo, err := s.cfg.Repos.Get(ctx, principal(ctx), name) | 50 | repo, err := s.cfg.Repos.Get(ctx, principal(ctx), name) | ||
| 51 | if err != nil { | 51 | if err != nil { | ||
M internal/adapters/web/tree.go +0 -2
| @@ -72,8 +72,6 @@ func (p TreePage) Unit() string { | |||
| 72 | 72 | ||
| 73 | 73 | // tree lists a directory of a ref, with the last commit of each entry. With | |
| 74 | 74 | // ?rows it answers the entries alone, for a directory opened in place. | |
| 75 | - | // | |
| 76 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the directory page from the use case results; no rule is decided here | |
| 77 | 75 | func (s *Server) tree(ctx context.Context, r *http.Request) (templ.Component, int, error) { | |
| 78 | 76 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | |
| 79 | 77 | if err != nil { | |
| @@ -72,8 +72,6 @@ func (p TreePage) Unit() string { | |||||
| 72 | 72 | ||||
| 73 | // tree lists a directory of a ref, with the last commit of each entry. With | 73 | // tree lists a directory of a ref, with the last commit of each entry. With | ||
| 74 | // ?rows it answers the entries alone, for a directory opened in place. | 74 | // ?rows it answers the entries alone, for a directory opened in place. | ||
| 75 | - | // | |||
| 76 | - | //hexcheck:ignore suspicious-business-logic-in-adapter builds the directory page from the use case results; no rule is decided here | |||
| 77 | func (s *Server) tree(ctx context.Context, r *http.Request) (templ.Component, int, error) { | 75 | func (s *Server) tree(ctx context.Context, r *http.Request) (templ.Component, int, error) { | ||
| 78 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | 76 | d, err := s.loadRepo(ctx, r.PathValue("repo")) | ||
| 79 | if err != nil { | 77 | if err != nil { | ||
M internal/adapters/webauthn/webauthn.go +0 -2
| @@ -137,8 +137,6 @@ func (v *Verifier) BeginLogin() ([]byte, []byte, error) { | |||
| 137 | 137 | ||
| 138 | 138 | // FinishLogin implements ports.PasskeyVerifier. The library compares the user | |
| 139 | 139 | // handle of the response with userHandle. | |
| 140 | - | // | |
| 141 | - | //hexcheck:ignore suspicious-business-logic-in-adapter copies the counter and backup state the library verified into the stored passkey; it decides nothing: the use case refuses a counter that does not advance | |
| 142 | 140 | func (v *Verifier) FinishLogin(userHandle []byte, ceremony, response []byte, lookup func(id []byte) (domain.Passkey, error)) (domain.Passkey, error) { | |
| 143 | 141 | var session gowebauthn.SessionData | |
| 144 | 142 | if err := json.Unmarshal(ceremony, &session); err != nil { | |
| @@ -137,8 +137,6 @@ func (v *Verifier) BeginLogin() ([]byte, []byte, error) { | |||||
| 137 | 137 | ||||
| 138 | // FinishLogin implements ports.PasskeyVerifier. The library compares the user | 138 | // FinishLogin implements ports.PasskeyVerifier. The library compares the user | ||
| 139 | // handle of the response with userHandle. | 139 | // handle of the response with userHandle. | ||
| 140 | - | // | |||
| 141 | - | //hexcheck:ignore suspicious-business-logic-in-adapter copies the counter and backup state the library verified into the stored passkey; it decides nothing: the use case refuses a counter that does not advance | |||
| 142 | func (v *Verifier) FinishLogin(userHandle []byte, ceremony, response []byte, lookup func(id []byte) (domain.Passkey, error)) (domain.Passkey, error) { | 140 | func (v *Verifier) FinishLogin(userHandle []byte, ceremony, response []byte, lookup func(id []byte) (domain.Passkey, error)) (domain.Passkey, error) { | ||
| 143 | var session gowebauthn.SessionData | 141 | var session gowebauthn.SessionData | ||
| 144 | if err := json.Unmarshal(ceremony, &session); err != nil { | 142 | if err := json.Unmarshal(ceremony, &session); err != nil { | ||