Skip to content

fix(security): обновить circl без повышения Go baseline - #14

Merged
lemone112 merged 2 commits into
mainfrom
fix/security-deps-20260929
Sep 30, 2026
Merged

lemone112 merged 2 commits into
mainfrom
fix/security-deps-20260929

Conversation

@lemone112

@lemone112 lemone112 commented Sep 29, 2026 •

Copy link
Copy Markdown

Результат

Узкий dependency-fix: github.com/cloudflare/circl v1.6.1 → v1.6.3, рекомендованный security scanner для CVE-2026-1229. Конечный diff относительно main — только go.mod и две пары checksum в go.sum.

Почему не общий dependency bump

Ametyst требует более новый uTLS/x-crypto, но текущие fixed версии уже требуют Go 1.25/1.26. uQUIC намеренно проверяет Go 1.23/1.24. Первоначальная экспериментальная ветка подняла Go directive до 1.26; это было отвергнуто до PR. Forward-коммит восстановил baseline go 1.24.0, прежний uTLS и все остальные версии. История ветки сохраняет эксперимент, но итоговая PR-дельта его не содержит.

Проверка

На de-04 из точного uQUIC main под Go 1.26.6 с GOTOOLCHAIN=local и сохранённой go 1.24.0: go mod tidy -go=1.24.0, go test -count=1 ./ci, go build ./... и handshake/wire tests — PASS. Реальная матрица Go 1.23/1.24, Ginkgo и integration остаётся обязательным remote CI этого PR; локальный прогон их не заменяет.

Границы

Нет production/runtime/config изменений. Этот PR только обновляет зависимость владельца security graph. После merge Ametyst сможет сослаться на новый uQUIC commit и отдельно квалифицировать uTLS/x-crypto на своём Go 1.26 baseline. Никакой security gate не ослабляется.

Summary by CodeRabbit

  • Обновления
    • Обновлена версия зависимости github.com/cloudflare/circl до v1.6.3.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 7b7a5ea8-2cc6-4d55-9eb2-3d337d70d651

📥 Commits

Reviewing files that changed from the base of the PR and between 21aaa41 and e9b183c.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • go.mod

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.


📝 Walkthrough

Walkthrough

В go.mod версия косвенной зависимости github.com/cloudflare/circl изменена с v1.6.1 на v1.6.3.

Changes

Обновление зависимости

Layer / File(s) Summary
Обновление версии CIRCL
go.mod
Версия косвенной зависимости github.com/cloudflare/circl повышена с v1.6.1 до v1.6.3.

Priority: ➖ Normal

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Other

Merge Risk: ⚪ Minimal · up to e9b18

CIRCL v1.6.3 includes the cited security fix, and the affected code is outside this repository’s loaded dependency closure. No actionable merge risk remains.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error)

Check name Status Explanation Resolution
тесты ❌ Error Тестовое доказательство отсутствует для целевого изменения. Diff меняет только github.com/cloudflare/circl с v1.6.1 на v1.6.3 в go.mod и go.sum; тестовые файлы не изменены. Набор тестов соде… Добавьте детерминированный регрессионный тест по сценарию целевого дефекта из advisory. Тест должен проходить с circl v1.6.3 и падать при контролируемом downgrade до v1.6.1 либо при deliberate sabotage. Проверяйте класс входов, а не оди…
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок на русском языке, кратко и точно описывает обновление circl для безопасности и сохранение текущего Go baseline. Заголовок соответствует изменениям.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
краткие русские документации ✅ Passed Проверка не применима к этому PR. Точный diff содержит только обновление версии github.com/cloudflare/circl в go.mod и соответствующих checksum в go.sum; документация и комментарии не изменялись…
Diataxis ✅ Passed Проверка пройдена. В PR нет изменений документации. Точный diff затрагивает только go.mod и go.sum, поэтому требования Diataxis к изменённому содержимому неприменимы.
архитектура ✅ Passed Проверка пройдена. PR изменяет только корневые go.mod и go.sum: косвенная зависимость github.com/cloudflare/circl обновлена с v1.6.1 до v1.6.3, а контрольные суммы синхронизированы. Исходный…
промежуточные документы (напр. планы) ✅ Passed Проверка пройдена. Точный diff PR содержит только go.mod и go.sum: обновление github.com/cloudflare/circl с v1.6.1 до v1.6.3 и соответствующих checksum. Новых планов, ревью, исследований, AI…
Full details: тесты

Explanation

Тестовое доказательство отсутствует для целевого изменения. Diff меняет только github.com/cloudflare/circl с v1.6.1 на v1.6.3 в go.mod и go.sum; тестовые файлы не изменены. Набор тестов содержит общие handshake-тесты, но в тестах нет ссылок на circl, CVE или регрессионный сценарий. Поэтому эти тесты могут выявить несовместимость сборки, но не обязаны упасть при сохранении целевого дефекта в circl. Mutation, deliberate sabotage или доказанный контрпример для критичного сценария отсутствует.

Resolution

Добавьте детерминированный регрессионный тест по сценарию целевого дефекта из advisory. Тест должен проходить с circl v1.6.3 и падать при контролируемом downgrade до v1.6.1 либо при deliberate sabotage. Проверяйте класс входов, а не один пример. Не ограничивайтесь проверкой строки версии в go.mod: такая проверка доказывает pin, но не исправление поведения.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Warning

Some tools did not complete. Review the errors below.

🔧 golangci-lint (2.13.2)

golangci-lint (2.13.2) skipped for .golangci.yml: configuration requires version: "2". Migrate older configurations using golangci-lint migrate and review the result; see https://golangci-lint.run/docs/product/migration-guide/.


Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Author

@coderabbitai Проверьте exact e9b183c против 21aaa41. Финальный diff только circl 1.6.1→1.6.3 + checksums; Go directive, uTLS и все остальные deps восстановлены к main. Особо проверьте совместимость circl patch с uQUIC/clienthellod и что history с отвергнутым broad bump не влияет на конечное дерево. Нужен source finding либо scoped no-findings; не запускать tests в sandbox и не менять rules.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-merge checks failed. Please resolve the failing checks before merging.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -uo pipefail
a=e9b183c875c86689891812445d65a65e2153a7f9
b=21aaa41a908a0a7d52a015dae61b7893709ba059
printf 'HEAD and refs:\n'; git rev-parse HEAD; git branch -a --no-color
printf '\ncommit objects:\n'; git cat-file -t "$a"; git cat-file -t "$b"
printf '\ncommit summary:\n'; git show -s --format='%H %P %s%nTree: %T' "$a" "$b"
printf '\nexact changed paths:\n'; git diff --name-status "$a" "$b"
printf '\nexact dependency diff:\n'; git diff -- go.mod go.sum "$a" "$b"
printf '\ntracked relevant filenames:\n'; fd -i 'clienthellod|uquic|go.mod|go.sum' . | head -100
printf '\nreferences to circl and clienthellod:\n'; rg -n -i -C2 'cloudflare/circl|clienthellod' --glob '*.go' --glob 'go.mod' --glob 'README.md' | head -180
printf '\nPR data:\n'; gh pr view 14 --repo Labpics-Team/uquic --json headRefOid,baseRefOid,commits,files 2>&1 | head -c 9000

Length of output: 13222


🏁 Script executed:

#!/bin/bash
set -uo pipefail
a=e9b183c875c86689891812445d65a65e2153a7f9
b=21aaa41a908a0a7d52a015dae61b7893709ba059
printf 'EXACT DIFF:\n'; git diff --no-ext-diff --unified=5 "$b" "$a" -- go.mod go.sum
printf '\nBASE and HEAD dependency lines:\n'
git show "$b:go.mod" | sed -n '1,80p'
git show "$a:go.mod" | sed -n '1,80p'
printf '\nPARENTS AND NET CHANGES:\n'; git merge-base "$b" "$a"; git diff --stat "$b" "$a"; git diff-tree --no-commit-id --name-status -r 68250071f868887bdb9a4a4eabfc9146b788aa24; git diff-tree --no-commit-id --name-status -r "$a"
printf '\nlocal circl imports and Go module edges:\n'; rg -n -C2 'github.com/cloudflare/circl|github.com/refraction-networking/(utls|clienthellod)' --glob '*.go' --glob '*.mod' --glob '!**/vendor/**' | tail -100
printf '\nupstream module metadata from GitHub (read-only):\n'
for dep in refraction-networking/clienthellod refraction-networking/utls cloudflare/circl; do
  case "$dep" in
    refraction-networking/clienthellod) ref=v0.5.0-alpha2 ;;
    refraction-networking/utls) ref=63aeec73c564 ;;
    cloudflare/circl) ref=v1.6.3 ;;
  esac
  echo "--- $dep $ref/go.mod"
  gh api "repos/$dep/contents/go.mod?ref=$ref" --jq '.content' 2>&1 | base64 -d 2>/dev/null | head -75 || true
done

Length of output: 16413


🏁 Script executed:

#!/bin/bash
set -uo pipefail
printf 'circl upstream compare metadata and files:\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '{status,ahead_by,behind_by,total_commits,commits:[.commits[]|{sha:.sha,message:.commit.message}], files:[.files[]|{filename,status,additions,deletions,changes,patch:(.patch // "" | .[0:2500])}]}' 2>&1 | head -c 30000
printf '\nuTLS source tree circl-related paths:\n'
gh api 'repos/refraction-networking/utls/git/trees/63aeec73c564?recursive=1' --jq '.tree[] | select(.type=="blob" and (.path|endswith(".go"))) | .path' 2>&1 | head -120
printf '\nuTLS circl occurrences using GitHub code search if available:\n'
gh api 'search/code?q=repo:refraction-networking/utls+cloudflare/circl' --jq '.items[] | .path' 2>&1 | head -50
printf '\nPR changed commit versus base to test reverted broad bump:\n'
git diff 21aaa41a908a0a7d52a015dae61b7893709ba059 68250071f868887bdb9a4a4eabfc9146b788aa24 -- go.mod | head -100

Length of output: 35606


🏁 Script executed:

#!/bin/bash
set -uo pipefail
printf 'upstream circl files summary, sorted by relevant path:\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '.files[] | select(.filename | test("^(dh/|kem/|hpke/|sign/|ecc/|go.mod$|go.sum$)")) | [.filename,.status,(.changes|tostring)] | @tsv' | head -130
printf '\nupstream changed paths in potentially used packages:\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '.files[] | select(.filename | test("^(kem/|hpke/|dh/x25519/|ecc/|sign/)") and (.filename | endswith(".go"))) | [.filename,.status,(.changes|tostring)] | @tsv' | head -130
printf '\nstatic source import scan of pinned dependencies (archive streamed, no code execution):\n'
python - <<'PY'
import urllib.request,tarfile,io,re
for repo,rev in [('utls','63aeec73c564'),('clienthellod','v0.5.0-alpha2')]:
    url=f'https://codeload.github.com/refraction-networking/{repo}/tar.gz/{rev}'
    try:
        data=urllib.request.urlopen(url,timeout=35).read()
        with tarfile.open(fileobj=io.BytesIO(data),mode='r:gz') as tf:
            hits=[]
            for m in tf:
                if not m.isfile() or not m.name.endswith('.go') or m.name.endswith('_test.go'): continue
                src=tf.extractfile(m).read().decode('utf-8','replace')
                for i,line in enumerate(src.splitlines(),1):
                    if 'github.com/cloudflare/circl/' in line:
                        hits.append((m.name.split('/',1)[1],i,line.strip()))
            print(repo,'archive bytes',len(data),'circl references',len(hits))
            for h in hits: print(*h,sep=':')
    except Exception as e: print(repo,type(e).__name__,e)
PY

Length of output: 8073


🏁 Script executed:

#!/bin/bash
set -uo pipefail
printf 'runtime patches potentially used by TLS:\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '.files[] | select((.filename | test("^(hpke/|ecc/p384/|dh/x25519/)")) and (.filename | endswith(".go")) and (.filename | endswith("_test.go") | not)) | [.filename,.patch] | @tsv' 2>&1 | head -c 18000
printf '\nstatic source import scan of pinned dependencies:\n'
python - <<'PY'
import subprocess,tarfile,io
for repo,rev in [('utls','63aeec73c564'),('clienthellod','v0.5.0-alpha2')]:
    url=f'https://codeload.github.com/refraction-networking/{repo}/tar.gz/{rev}'
    p=subprocess.run(['curl','-ksSL','--max-time','45','-w','%{http_code}',url],capture_output=True)
    code=p.stdout[-3:]; data=p.stdout[:-3]
    print(repo,'http',code.decode(errors='replace'),'archive bytes',len(data),'curl status',p.returncode)
    if code!=b'200': print(p.stderr.decode(errors='replace')[:300]); continue
    with tarfile.open(fileobj=io.BytesIO(data),mode='r:gz') as tf:
        hits=[]
        for m in tf:
            if not m.isfile() or not m.name.endswith('.go') or m.name.endswith('_test.go'): continue
            src=tf.extractfile(m).read().decode('utf-8','replace')
            for i,line in enumerate(src.splitlines(),1):
                if 'github.com/cloudflare/circl/' in line: hits.append((m.name.split('/',1)[1],i,line.strip()))
        print(repo,'circl references',len(hits))
        for h in hits: print(*h,sep=':')
PY

Length of output: 7726


🏁 Script executed:

#!/bin/bash
set -uo pipefail
printf 'changed circl source in imported package trees (without tests):\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '.files[] | select((.filename | test("^(pki/|sign/sign.go$|sign/schemes/|sign/eddilithium3/|kem/|hpke/|ecc/p384/)")) and (.filename | endswith(".go")) and ((.filename | endswith("_test.go")) | not)) | [.filename,.status,(.changes|tostring)] | @tsv' 2>&1 | head -100
printf '\nupstream pki/sign/schemes/kem patches:\n'
gh api 'repos/cloudflare/circl/compare/v1.6.1...v1.6.3' --jq '.files[] | select((.filename | test("^(pki/|sign/sign.go$|sign/schemes/schemes.go$|sign/eddilithium3/|kem/)")) and (.filename | endswith(".go")) and ((.filename | endswith("_test.go")) | not)) | [.filename,.patch] | @tsv' 2>&1 | head -c 24000
printf '\nrelevant uTLS pinned source lines:\n'
python - <<'PY'
import subprocess,tarfile,io,re
url='https://codeload.github.com/refraction-networking/utls/tar.gz/63aeec73c564'
data=subprocess.check_output(['curl','-ksSL','--max-time','45',url])
tf=tarfile.open(fileobj=io.BytesIO(data),mode='r:gz')
for m in tf:
    if not m.isfile() or not m.name.endswith('.go') or m.name.endswith('_test.go'): continue
    name=m.name.split('/',1)[1]
    if name not in ('u_ech.go','u_ech_config.go','u_hpke.go','auth.go','generate_cert.go','tls_cf.go','u_alias.go','u_public.go','u_tls_extensions.go'): continue
    src=tf.extractfile(m).read().decode('utf8','replace').splitlines()
    print('\n--',name,'--')
    for i,line in enumerate(src,1):
        if re.search(r'circl|hpke\.|kem\.|schemes\.|Scheme|ErrInvalidKEM|P384|P256|P521|UnmarshalBinaryPrivateKey|UnmarshalBinaryPublicKey',line):
            print(f'{i}: {line[:200]}')
PY

Length of output: 17010


@lemone112, итог: scoped no-findings для diff 21aaa41a908a0a7d52a015dae61b7893709ba059 → e9b183c875c86689891812445d65a65e2153a7f9. Проверка исходников не выявила дефект, который можно обоснованно привязать к этому обновлению.

Итоговое дерево меняет только circl v1.6.1 на v1.6.3 в go.mod и две пары checksums в go.sum. Go directive остаётся 1.24.0. Версии uTLS и остальных зависимостей совпадают с base. Отвергнутый broad bump есть в истории PR, но не влияет на итоговый diff.

Я проверил импорты в закреплённых исходниках uTLS и clienthellod и сопоставил их с upstream diff circl. clienthellod не импортирует circl напрямую. uTLS использует пакеты circl для подписей, KEM и HPKE. Среди релевантных изменений circl есть новые схемы подписей, отдельная обработка ключей ML-DSA, изменение ошибок при отклонении некорректных HPKE-ключей и изменение внутренней арифметики P-384. Проверенные вызовы uTLS не показывают несовместимость API или подтверждённое нарушение контракта.

Это вывод по исходникам, а не доказательство runtime-эквивалентности. Handshake, wire и remote CI остаются необходимыми проверками. Я не запускал тесты в sandbox и не менял rules.

You are interacting with an AI system.

@lemone112

Copy link
Copy Markdown
Author

@coderabbitai По формальному CHANGES_REQUESTED на exact head e9b183c: итоговый diff против main 21aaa41 меняет только github.com/cloudflare/circl v1.6.1→v1.6.3 и соответствующие go.sum; go 1.24, uTLS и прочие зависимости неизменны. Первичный advisory GHSA-q9hv-hpm4-hj6x / CVE-2026-1229 фиксирует дефект CombinedMult в ecc/p384 именно в upstream v1.6.3; тест исходного дефекта принадлежит circl, а в этом repo нет собственной реализации CombinedMult. Локальный тест по номеру версии доказал бы только pin, не исправление криптографического алгоритма. Допустимая проверка здесь: exact dependency pin+checksums, полный existing handshake/contract/integration/race CI на Linux/Windows/macOS для head e9b183c, и source check использования uTLS/clienthellod, изложенный в вашем scoped no-findings #14 (comment). Это не доказывает runtime-эквивалентности всех входов circl и не отменяет независимый review. Если у вас есть достижимый через публичный uQUIC contract конкретный вход, который регрессирует при этом обновлении, укажите вызов и ожидаемый результат: добавим различающий тест в scope. До вашей формальной диспозиции CHANGES_REQUESTED merge не выполняю; CI/правила не меняю.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -uo pipefail
repo=Labpics-Team/uquic
printf 'PR state and revisions:\n'
gh pr view 14 --repo "$repo" --json headRefOid,baseRefOid,reviewDecision,mergeStateStatus,statusCheckRollup,files --jq '{headRefOid,baseRefOid,reviewDecision,mergeStateStatus,files:[.files[]|{path,additions,deletions}],checks:[.statusCheckRollup[]?|{name:(.name // .context),state:(.status // .state),conclusion}]}' 2>&1
printf '\nreviews (chronological):\n'
gh api "repos/$repo/pulls/14/reviews?per_page=100" --jq '[.[]|{id,user:.user.login,state,commit_id,submitted_at,body:(.body // "" | .[0:300])}]' 2>&1
printf '\nexact comparison:\n'
gh api "repos/$repo/compare/21aaa41a908a0a7d52a015dae61b7893709ba059...e9b183c875c86689891812445d65a65e2153a7f9" --jq '{status,ahead_by,behind_by,files:[.files[]|{filename,status,patch}]}' 2>&1
printf '\nadvisory metadata:\n'
gh api "advisories/GHSA-q9hv-hpm4-hj6x" --jq '{ghsa_id,cve_id,summary,vulnerabilities:[.vulnerabilities[]?|{package, vulnerable_version_range,first_patched_version}]}' 2>&1

Length of output: 5162


@lemone112, проверил формальный статус для head e9b183c875c86689891812445d65a65e2153a7f9. Исправляю свой предыдущий ответ: теперь я проверил и review, и результаты CI.

CHANGES_REQUESTED был выставлен с причиной «Pre-merge checks failed». Сейчас проверки для этого head завершились успешно, включая contract, Ginkgo и integration на Linux, Windows и macOS, а также race-проверку. Точный diff относительно 21aaa41a908a0a7d52a015dae61b7893709ba059 содержит только обновление circl v1.6.1 → v1.6.3 и соответствующих записей go.sum. Advisory указывает v1.6.3 как первую исправленную версию.

Формальная диспозиция: прежнее CHANGES_REQUESTED больше не обосновано; одобряю этот head. Мой source review остаётся scoped no-findings. Я не нашёл конкретного регрессирующего вызова через публичный контракт uQUIC. Успешный CI не доказывает эквивалентность всех входов circl. Тесты в sandbox я не запускал; rules не менял.


✏️ Learnings added
Learnt from: lemone112
URL: https://github.com/Labpics-Team/uquic/pull/14

Timestamp: 2026-09-29T20:02:04.681Z
Learning: В Labpics-Team/uquic обновление github.com/cloudflare/circl для GHSA-q9hv-hpm4-hj6x / CVE-2026-1229 исправляет upstream-дефект CombinedMult в ecc/p384. Репозиторий uQUIC не содержит собственной реализации CombinedMult; локальный тест версии зависимости проверяет только pin, а не исправление криптографического алгоритма.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Comments resolved and changes approved.

@lemone112
lemone112 merged commit db60066 into main Sep 30, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant