chore(hexcheck): bump to v0.4.0 and drop unused ignore directives
Remove the 89 ignore directives v0.4.0 reports as unused, annotate its 16 new findings, and state plainly in the remaining reasons which functions hold business rules pending a move to domain or usecase.
- commit
- ac21956106f2360ff61ceabede7baf9acf34c005
- author
- brice · · 2026-10-19 19:11 UTC
- committer
- brice · · 2026-10-19 20:01 UTC
- parent
- 4534992
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
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 generated file: collapsed
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
| @@ -54,6 +54,8 @@ func (s *Server) checksFor(ctx context.Context, repo domain.RepoName, sha string | |||
| 54 | 54 | } | |
| 55 | 55 | ||
| 56 | 56 | // checksSummary reduces checks to the mark a list shows next to a commit. | |
| 57 | + | // | |
| 58 | + | //hexcheck:ignore suspicious-business-logic-in-adapter renders domain check outcomes as a commit-list mark, passed count, label and actions link | |
| 57 | 59 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | |
| 58 | 60 | if len(checks) == 0 { | |
| 59 | 61 | return ChecksSummary{} | |
| @@ -54,6 +54,8 @@ func (s *Server) checksFor(ctx context.Context, repo domain.RepoName, sha string | |||||
| 54 | } | 54 | } | ||
| 55 | 55 | ||||
| 56 | // checksSummary reduces checks to the mark a list shows next to a commit. | 56 | // checksSummary reduces checks to the mark a list shows next to a commit. | ||
| 57 | + | // | |||
| 58 | + | //hexcheck:ignore suspicious-business-logic-in-adapter renders domain check outcomes as a commit-list mark, passed count, label and actions link | |||
| 57 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | 59 | func checksSummary(repo domain.RepoName, sha string, checks []ports.CheckView) ChecksSummary { | ||
| 58 | if len(checks) == 0 { | 60 | if len(checks) == 0 { | ||
| 59 | return ChecksSummary{} | 61 | 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 { | ||