diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d19cebb..24bc05b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,6 +88,30 @@ jobs: - name: Unit tests run: pnpm --filter ./apps/web test + - name: A green run must have executed tests + working-directory: apps/web + # vitest exits 1 when no test file matches, so a suite that vanishes + # entirely is already caught. A suite that shrinks is not: 172 -> 1 exits + # 0. This is the same floor the android and ios-core jobs carry, and web + # is the largest suite of the four. + run: | + set -euo pipefail + npx vitest run --reporter=json --outputFile=/tmp/vitest.json + python3 - <<'PY_EOF' + import json, sys + d = json.load(open("/tmp/vitest.json")) + total = d.get("numTotalTests", 0) + passed = d.get("numPassedTests", 0) + failed = d.get("numFailedTests", 0) + print(f"{passed} passed, {failed} failed, {total} total") + # 172, the exact count on 2026-09-03. See the android floor for why exact. + FLOOR = 172 + if total < FLOOR: + sys.exit(f"only {total} web tests ran; expected at least {FLOOR}") + if failed: + sys.exit("the suite reported failures") + PY_EOF + # Nothing built the app until 2026-08-19. Tests and svelte-check both run # against source, so a break that only appears in a production build — # the wasm and pdf-worker copy steps, the Cloudflare adapter, a @@ -185,11 +209,47 @@ jobs: run: go build ./... - name: go test - # NOTE: there are currently zero *_test.go files here, so this passes - # vacuously. It is kept because it turns the moment someone adds a test - # into a real gate, and because `[no test files]` in the log is an - # honest signal. It is not evidence the service works. - run: go test ./... + # This comment read "there are currently zero *_test.go files here, so + # this passes vacuously" until 2026-09-03. There are 8, with 26 test + # functions across 4 packages, and they pass. The comment was stale in + # the safe direction, which is the expensive kind: it is why this job + # never got the count assertion the android and ios-core jobs both have, + # so 26 tests could have vanished here without the job noticing. + run: go test ./... -count=1 + + - name: A green run must have executed tests + # `go test` exits 0 for a package with no test files, printing + # `[no test files]`. So the exit code cannot distinguish a passing suite + # from a deleted one. Same argument as the android floor below. + run: | + set -euo pipefail + go test ./... -count=1 -json > /tmp/go-test.json + python3 - <<'PY_EOF' + import json, sys + ran = set() + with open("/tmp/go-test.json") as f: + for line in f: + line = line.strip() + if not line: + continue + ev = json.loads(line) + if ev.get("Action") == "pass" and ev.get("Test"): + ran.add((ev["Package"], ev["Test"])) + print(f"{len(ran)} Go tests passed") + # 60, the exact count on 2026-09-03, measured twice for stability: 26 + # top-level functions plus 34 `t.Run` subtests. Counting subtests is + # deliberate — `go test -json` emits a pass event per subtest, so this + # catches a deleted table row and not only a deleted function, which is + # stronger than a `func Test` grep. If a table is refactored, the number + # moves for a legitimate reason; bump it in that commit. + # + # Exact rather than a margin, for the reason the android floor states: + # adding tests never trips a floor, so the only thing a floor catches is + # a removal, and a removal should be deliberate. + FLOOR = 60 + if len(ran) < FLOOR: + sys.exit(f"only {len(ran)} Go tests ran; expected at least {FLOOR}") + PY_EOF - name: govulncheck run: | @@ -197,23 +257,12 @@ jobs: "$(go env GOPATH)/bin/govulncheck" ./... cli: - # apps/cli is the batch and desktop surface (ADR-0004). It depends on the - # monocr-onnx Rust library, which is a SIBLING REPOSITORY, so this job - # currently checks out both. That is a stopgap: once the tiling work in that - # crate is released, Cargo.toml should point at a pinned git rev and the - # second checkout goes away. A path dependency on a sibling checkout is the - # documented reason mon-vlm's CI cannot run at all. + # apps/cli is the batch and desktop surface (ADR-0004). It takes the OCR + # library from crates.io, so this job needs no sibling checkout and builds + # what a consumer actually gets. runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - path: monocr - - - name: Check out the sibling SDK the CLI depends on - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - repository: MonDevHub/monocr-onnx - path: monocr-onnx - uses: dtolnay/rust-toolchain@stable @@ -227,22 +276,57 @@ jobs: run: sudo apt-get update && sudo apt-get install -y poppler-utils - name: cargo fmt - working-directory: monocr/apps/cli + working-directory: apps/cli run: cargo fmt --check - name: cargo clippy - working-directory: monocr/apps/cli + working-directory: apps/cli run: cargo clippy --all-targets -- -D warnings - name: cargo test - working-directory: monocr/apps/cli + working-directory: apps/cli run: cargo test + - name: A green run must have executed tests + working-directory: apps/cli + # `cargo test` exits 0 for a crate with no tests, printing "running 0 + # tests", so the exit code cannot tell a passing suite from a deleted + # one. That is the hole the web, go and android floors close; cli was the + # fourth surface and the last one without a floor. + # + # Parsed from `test result:` lines with an explicit FAILED check, because + # a grep that matches nothing reads as a pass. `--format json` is not used + # here: it still requires `-Z unstable-options`, so it would tie this gate + # to a nightly toolchain while the job runs `dtolnay/rust-toolchain@stable`. + run: | + set -euo pipefail + cargo test > /tmp/cargo-test.txt 2>&1 || { + cat /tmp/cargo-test.txt + exit 1 + } + python3 - <<'PY_EOF' + import re, sys + text = open("/tmp/cargo-test.txt").read() + if re.search(r"^test result: FAILED", text, re.M): + sys.exit("the suite reported failures") + runs = [int(m) for m in re.findall(r"^test result: ok\. (\d+) passed", text, re.M)] + if not runs: + sys.exit("no 'test result:' line in cargo's output: the suite did not run") + passed = sum(runs) + print(f"{passed} Rust tests passed across {len(runs)} binaries") + # 68, the exact count on 2026-09-03. Exact rather than a margin, for the + # reason the android floor states: adding tests never trips a floor, so the + # only thing a floor catches is a removal, and a removal should be deliberate. + FLOOR = 68 + if passed < FLOOR: + sys.exit(f"only {passed} Rust tests ran; expected at least {FLOOR}") + PY_EOF + - name: The tiling fixture is not optional # The fixture is the only thing keeping four language ports in step. If # it goes missing, every port's parity test silently has nothing to # compare against. - working-directory: monocr + working-directory: . run: | set -euo pipefail f=shared/segmentation-fixtures/tiling-cases.json @@ -267,7 +351,7 @@ jobs: # from it at borders and on even-width kernels. A fixture regenerated by # someone who did not read that would flip 23 pixels across two cases and # look like a routine refresh, so the constants are asserted here too. - working-directory: monocr + working-directory: . run: | set -euo pipefail f=shared/segmentation-fixtures/rule-cases.json @@ -303,7 +387,7 @@ jobs: # throughout because iOS compared itself against an oracle that was also a # square. The half-width table below IS the kernel shape, so a fixture that # went missing or got hand-edited would un-gate the thing that found it. - working-directory: monocr + working-directory: . run: | set -euo pipefail f=shared/segmentation-fixtures/dilate-cases.json @@ -343,7 +427,7 @@ jobs: # `merge_runs` is what stands between raw-profile boundary detection and a # 22x garbage regression, and it exists ten times in five languages. Parity # across those ten was checked once, by hand, before this fixture existed. - working-directory: monocr + working-directory: . run: | set -euo pipefail f=shared/segmentation-fixtures/merge-cases.json @@ -477,8 +561,22 @@ jobs: failures += int(root.get("failures", 0)) errors += int(root.get("errors", 0)) print(f"{tests} tests in {len(files)} classes, {failures} failures, {errors} errors") - if tests < 40: - sys.exit(f"only {tests} tests ran; the suite has had 50 since 2026-08-28") + # 106, the exact count on 2026-09-03. Raised from 40 that day, where the + # comment beside it read "the suite has had 50 since 2026-08-28" — so the + # floor was stale against its own comment, and its own comment was stale + # against the suite. 66 tests could have vanished silently. + # + # Exact rather than a margin, deliberately. Adding tests never trips a floor, + # so the only thing this can catch is a removal, and a removal is exactly what + # should be deliberate. If this fails, either a test was lost or one was merged + # into another: bump the number in the same commit that removes the test, and + # the diff then records the removal. + FLOOR = 106 + if tests < FLOOR: + sys.exit( + f"only {tests} tests ran; expected at least {FLOOR}. Either the suite " + "lost tests or a test was merged away. Bump FLOOR in the same commit." + ) if failures or errors: sys.exit("the suite reported failures") PY diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml new file mode 100644 index 0000000..b1acb4b --- /dev/null +++ b/.github/workflows/release-cli.yml @@ -0,0 +1,109 @@ +# Publishes the `monocr-cli` crate to crates.io on a `cli/v*` tag. +# +# Trusted publishing (OIDC), so no CARGO_REGISTRY_TOKEN is stored here. +# +# ONE-TIME SETUP on crates.io, after a crate exists (crates.io has no +# pending-publisher mechanism, unlike PyPI — see monocr-onnx/RELEASING.md): +# https://crates.io/crates/monocr-cli/settings -> trusted publisher +# owner MonDevHub · repo monocr · workflow release-cli.yml +# environment: crates-io +# +# `environment` must match the job's `environment:` below. A job that declares +# one puts an `environment` claim in the OIDC token, and crates.io matches the +# whole claim set — a publisher registered as blank rejects a token carrying one. +# +# 0.1.0 was published by hand on 2026-09-03, so the first tag this can succeed +# on is a higher version: crates.io refuses duplicates and the gate below +# refuses a tag that disagrees with Cargo.toml. Bump, then tag. +# +# Tag is `cli/v*`, not a bare `v*`: this repo ships four surfaces and has no +# tags yet, so a bare prefix would become ambiguous the moment a second one does. +name: release-cli.yml +# Environment: crates-io +# Before step 2 is done, this workflow's OIDC token exchange is refused. +# +# The environment field must say `crates-io`, not be left blank. This block +# said blank while the job below declares `environment: crates-io`, and the +# two cannot both be right: a job that declares an environment puts an +# `environment` claim in the OIDC token, and crates.io matches the whole +# claim set. A publisher registered with a blank environment rejects a token +# that carries one. +# +# Step 1 has already happened: monocr-cli 0.1.0 was published by hand on +# 2026-09-03. So the FIRST tag this workflow can succeed on is a version +# above 0.1.0 — crates.io refuses a duplicate, and the gate below refuses a +# tag that disagrees with Cargo.toml. Bump the version, then tag. +# +# The tag is namespaced `cli/v*` rather than a bare `v*` even though this is +# the only thing this monorepo currently publishes: the repository has zero +# git tags today across four shipped surfaces (web, iOS, Android, CLI), and a +# bare `v*` would become ambiguous the moment any of the others gets one. +name: release-cli + +on: + push: + tags: + - "cli/v*" + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + # Attach a protected environment named `crates-io` in repository settings + # for a manual approval step before this leaves the machine, mirroring + # mon_tokenizer's `environment: pypi`. GitHub creates it with no + # protection rules on first use if it does not exist, so this is safe + # either way. + environment: crates-io + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: dtolnay/rust-toolchain@stable + + # poppler is a runtime dependency of the PDF path, and the renderer's + # tests fail rather than skip without it. + - name: poppler + run: sudo apt-get update && sudo apt-get install -y poppler-utils + + # A tag that disagrees with Cargo.toml publishes the wrong number + # under the right name, and crates.io has no undo. + - name: Verify the tag matches Cargo.toml + working-directory: apps/cli + run: | + set -euo pipefail + TAG="${GITHUB_REF_NAME#cli/v}" + PKG="$(awk -F'"' '/^version = /{print $2; exit}' Cargo.toml)" + if [ "$TAG" != "$PKG" ]; then + echo "::error title=Tag/version mismatch::tag cli/v$TAG does not match Cargo.toml version $PKG" + exit 1 + fi + echo "tag and Cargo.toml agree on $PKG" + + # Mirrors the cli job in ci.yml: fmt, clippy, test. Not a divergent, + # invented gate — the same three checks that already run on every push. + - name: cargo fmt + working-directory: apps/cli + run: cargo fmt --check + + - name: cargo clippy + working-directory: apps/cli + run: cargo clippy --all-targets -- -D warnings + + - name: cargo test + working-directory: apps/cli + run: cargo test + + - name: Authenticate with crates.io + id: auth + uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 + + - name: Publish + working-directory: apps/cli + run: cargo publish + env: + CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} diff --git a/.gitleaksignore b/.gitleaksignore index 24186f7..08240dc 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -8,3 +8,18 @@ # the key is rotated and you want the reminder gone. d026e3d9696abe2eddac47d983fa245599512b3e:apps/android/app/src/main/java/dev/janakhpon/monocr/engine/SyncWorker.kt:generic-api-key:16 d026e3d9696abe2eddac47d983fa245599512b3e:apps/ios/monocr-ios/SyncService.swift:generic-api-key:9 + +# Two test placeholders, not secrets. Both lines are literally +# `const key = "0123456789abcdef"` repeated four times, inside tests named +# TestPanicLogDoesNotCarryTheApiKey and TestRecoveryMiddlewareDoesNotLogTheApiKey +# — tests whose whole point is asserting a key never reaches a log. 64 hex chars +# of ascending nibbles trips gitleaks' generic-api-key entropy rule. +# +# Ignored by fingerprint rather than an inline `// gitleaks:allow` because the +# scan is `gitleaks detect` over full history: the finding is anchored to commit +# f4de7ba and would keep being reported no matter what the working tree says. +# +# This is what had the secrets job red since 2026-08-28, on every run, with +# nothing actually leaked. +f4de7ba5c5c208ab8e90b7bded85dbaf37fb7cda:services/feedback/internal/middleware/recovery_endtoend_test.go:generic-api-key:21 +f4de7ba5c5c208ab8e90b7bded85dbaf37fb7cda:services/feedback/internal/middleware/recovery_redact_test.go:generic-api-key:17 diff --git a/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/DilateFixtureTest.kt b/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/DilateFixtureTest.kt index 2ccccb4..8388db4 100644 --- a/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/DilateFixtureTest.kt +++ b/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/DilateFixtureTest.kt @@ -96,7 +96,9 @@ class DilateFixtureTest { @Test fun `the dilation kernel matches the reference rule`() { val rule = fixture["kernel_for_small_height"].asJsonObject - assertTrue("the fixture carried no kernel rule", rule.size() > 0) + // A floor, for the reason `half_widths` above already gives. This table + // held 13 heights against a check that one would satisfy. + assertTrue("kernel rule shrank to ${rule.size()}", rule.size() >= 13) for ((heightText, expected) in rule.entrySet()) { val height = heightText.toInt() assertEquals( @@ -114,7 +116,9 @@ class DilateFixtureTest { @Test fun `the corner patch matches the reference rule`() { val rule = fixture["corner_patch_for_side"].asJsonObject - assertTrue("the fixture carried no corner rule", rule.size() > 0) + // 12 sides, likewise. The docstring above notes a mutation that survived + // the whole suite here; a table that may shrink to one entry is how. + assertTrue("corner rule shrank to ${rule.size()}", rule.size() >= 12) for ((sideText, expected) in rule.entrySet()) { val side = sideText.toInt() assertEquals("corner patch for a side of $side", expected.asInt, PageNormalizer.cornerPatch(side)) diff --git a/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/LineTilerFixtureTest.kt b/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/LineTilerFixtureTest.kt index 7125b91..d428510 100644 --- a/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/LineTilerFixtureTest.kt +++ b/apps/android/app/src/test/java/dev/janakhpon/monocr/engine/LineTilerFixtureTest.kt @@ -112,7 +112,11 @@ class LineTilerFixtureTest { @Test fun `cut column probes land where the reference implementation puts them`() { val probes = fixture["cut_column_probes"].asJsonArray - assertTrue("fixture has no cut column probes", probes.size() > 0) + // A floor, not emptiness. Web and iOS both require three + // (segmentation.test.ts:75, LineTilingTests.swift:175); this port asked + // only for one, so the probe set could shrink 3 -> 1 and Android alone + // stayed green. That is the asymmetry a shared fixture exists to remove. + assertTrue("cut column probes shrank to ${probes.size()}", probes.size() >= 3) for (element in probes) { val probe = element.asJsonObject diff --git a/apps/cli/Cargo.lock b/apps/cli/Cargo.lock index fcbdcbd..3d00826 100644 --- a/apps/cli/Cargo.lock +++ b/apps/cli/Cargo.lock @@ -1056,40 +1056,42 @@ dependencies = [ ] [[package]] -name = "monocr-cli" -version = "0.1.0" +name = "monocr" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cacdb37146ee069357706f7454d4c9f103506a93b6a249acd71e6316388f5c91" dependencies = [ "anyhow", - "assert_fs", "clap", + "dirs", "image", - "monocr-onnx", + "indicatif", + "ndarray", "ort", + "reqwest", "serde", "serde_json", - "serde_yaml", - "sha2", "tempfile", "tokio", - "walkdir", ] [[package]] -name = "monocr-onnx" -version = "0.3.0" +name = "monocr-cli" +version = "0.1.0" dependencies = [ "anyhow", + "assert_fs", "clap", - "dirs", "image", - "indicatif", - "ndarray", + "monocr", "ort", - "reqwest", "serde", "serde_json", + "serde_yaml", + "sha2", "tempfile", "tokio", + "walkdir", ] [[package]] diff --git a/apps/cli/Cargo.toml b/apps/cli/Cargo.toml index 88630c3..03722ed 100644 --- a/apps/cli/Cargo.toml +++ b/apps/cli/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2021" description = "Batch Mon OCR over books, PDFs and images, on-device" license = "MIT" +repository = "https://github.com/MonDevHub/monocr/tree/main/apps/cli" +homepage = "https://github.com/MonDevHub/monocr/tree/main/apps/cli" [[bin]] name = "monocr-cli" @@ -14,15 +16,14 @@ path = "src/main.rs" # reimplementation of the recogniser: segmentation, tiling, the model pin and # the charset contract all live upstream. # -# TODO(before CI): this must become a pinned git rev, not a path. A path -# dependency on a sibling checkout is a known failure mode in this ecosystem — -# mon-lm records that "mon-vlm took an editable path install of it and that is -# why mon-vlm's CI cannot run at all: uv sync fails on any machine without -# mon_OCR checked out alongside". The path is here only so the CLI builds -# against uncommitted upstream work; swap it for -# monocr-onnx = { git = "https://github.com/MonDevHub/monocr-onnx", rev = "..." } -# once the tiling change lands, and keep the rev pinned. -monocr-onnx = { path = "../../../monocr-onnx/rust" } +# A registry dependency, not a path into a sibling checkout — a path made this +# crate unpublishable (crates.io rejects path and git deps) and made CI depend +# on a second checkout being present and at the right revision. +# +# `package = "monocr"` with the key left as `monocr-onnx`: the published crate +# is named `monocr`, and Cargo takes the extern crate name from the KEY, so +# this keeps every `monocr_onnx::` reference in src/main.rs compiling. +monocr-onnx = { version = "0.3.1", package = "monocr" } # Pinned exactly, not by range. ort is a pre-release and "2.0.0-rc.11" # range-matches rc.13, which changed Send bounds and does not compile diff --git a/apps/cli/README.md b/apps/cli/README.md index 3b1887a..2231030 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -1,5 +1,7 @@ # monocr-cli +[![crates.io](https://img.shields.io/crates/v/monocr-cli.svg)](https://crates.io/crates/monocr-cli) + Extract Mon text from books, PDFs and images, on-device and in batch. This is the batch and desktop surface for MonOCR. The apps read one page at a time through a @@ -22,14 +24,25 @@ before it; a sixth would be a liability. See [ADR-0004](../../docs/architecture/ ## Install -Needs Rust and poppler (`pdftoppm`, `pdfinfo`) for the PDF path. +Needs poppler (`pdftoppm`, `pdfinfo`) for the PDF path, either way. ```bash brew install poppler # macOS apt-get install poppler-utils # Debian +``` + +From [crates.io](https://crates.io/crates/monocr-cli): + +```bash +cargo install monocr-cli +monocr-cli download # prime the model cache before a long run +``` +Or from this checkout: + +```bash cargo build --release -./target/release/monocr-cli download # prime the model cache before a long run +./target/release/monocr-cli download ``` Without poppler the renderer's tests **fail** rather than skipping. That is diff --git a/apps/ios/Scripts/swift-test.sh b/apps/ios/Scripts/swift-test.sh index 07eb978..1acb47a 100755 --- a/apps/ios/Scripts/swift-test.sh +++ b/apps/ios/Scripts/swift-test.sh @@ -42,9 +42,37 @@ STATUS=0 swift test --package-path MonOcrCore --disable-xctest $FLAGS >"$LOG" 2>&1 || STATUS=$? cat "$LOG" +# Two checks, because presence was not enough. Until 2026-09-03 this only grepped for +# the string "Test run with", so the suite could shrink from 73 tests to 1 and still be +# called a pass — the same defect the Android job's count floor exists to prevent, and +# the same one this wrapper's own comment invokes when the Android job cites it. if ! grep -q "Test run with" "$LOG"; then echo "swift-test: the run reported no test count, so it ran no tests. Not calling that a pass." >&2 exit 1 fi +# The line is: "Test run with 73 tests in 12 suites passed after 7.234 seconds." +# Format verified 2026-09-03 by running this script against MonOcrCore. +COUNT="$(sed -n 's/.*Test run with \([0-9][0-9]*\) tests.*/\1/p' "$LOG" | tail -1)" + +# 73, the exact count on 2026-09-03. Exact rather than a margin for the reason the +# Android floor gives: adding tests never trips a floor, so the only thing this can catch +# is a removal, and a removal should be deliberate. If this fails, bump FLOOR in the same +# commit that removes the test so the diff records it. +FLOOR=73 + +if [ -z "$COUNT" ]; then + echo "swift-test: found the summary line but could not read a count from it. The" >&2 + echo " format may have changed; fix the parse rather than deleting this check." >&2 + exit 1 +fi + +if [ "$COUNT" -lt "$FLOOR" ]; then + echo "swift-test: only $COUNT tests ran; expected at least $FLOOR." >&2 + echo " Either the suite lost tests or one was merged away. Bump FLOOR in the same commit." >&2 + exit 1 +fi + +echo "swift-test: $COUNT tests ran (floor $FLOOR)." + exit "$STATUS" diff --git a/services/feedback/go.mod b/services/feedback/go.mod index 527b90f..5a3870d 100644 --- a/services/feedback/go.mod +++ b/services/feedback/go.mod @@ -64,7 +64,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/quic-go/qpack v0.6.0 // indirect - github.com/quic-go/quic-go v0.59.0 // indirect + github.com/quic-go/quic-go v0.59.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect diff --git a/services/feedback/go.sum b/services/feedback/go.sum index 487edfd..a280a8d 100644 --- a/services/feedback/go.sum +++ b/services/feedback/go.sum @@ -122,8 +122,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= -github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic= +github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=