Compare commits

...
4 Commits
Author SHA1 Message Date
DenozordecandCursor b51a9ae3b3 ci: add ci type to release configuration and update documentation
CI / changes (push) Successful in 7s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 31s
CI / web (push) Successful in 41s
CI / go (push) Successful in 47s
CI / bird2 (push) Successful in 19s
CI / release (push) Successful in 3m47s
- Introduced `ci` type in `.releaserc.json` for patch releases.
- Updated conventional commits documentation to reflect the new `ci` type and its implications for versioning.
- Clarified the role of `ci` in the context of patch releases in the releasing guide.

Co-authored-by: Cursor <[email protected]>
2026-05-20 15:24:21 +07:00
DenozordecandCursor 4d4cd2301f ci: update golangci-lint version and installation mode
CI / changes (push) Successful in 7s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 23s
CI / web (push) Successful in 30s
CI / go (push) Successful in 1m15s
CI / bird2 (push) Successful in 15s
CI / release (push) Successful in 18s
- Upgraded golangci-lint from v1.62 to v1.64.8 to ensure compatibility with Go 1.24.
- Changed installation mode to 'goinstall' for improved setup.

Co-authored-by: Cursor <[email protected]>
2026-05-20 15:18:53 +07:00
DenozordecandCursor d687881eaa chore: update golangci configuration and improve resource cleanup
CI / changes (push) Successful in 7s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 23s
CI / web (push) Successful in 31s
CI / go (push) Failing after 19s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
- Disabled all linters in .golangci.yml to streamline linting process.
- Updated resource cleanup in multiple files to use deferred functions for closing response bodies, ensuring proper error handling and resource management.

Co-authored-by: Cursor <[email protected]>
2026-05-20 15:13:02 +07:00
DenozordecandCursor 87e756f34f ci: expand changes detection to rewire all pipeline nodes
CI / changes (push) Successful in 7s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 28s
CI / web (push) Successful in 40s
CI / go (push) Failing after 21s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
Полный прогон при scripts/*, workflows, golangci, pre-commit; openapi в full_pipeline; миграции и deploy-пути; исправлен fallback пустого diff.

Co-authored-by: Cursor <[email protected]>
2026-05-20 15:08:28 +07:00
25 changed files with 164 additions and 121 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ powershell -NoProfile -File scripts/commit/staged-context.ps1
| `refactor` | реструктуризация **без** новой возможности и **без** исправления бага | — | | `refactor` | реструктуризация **без** новой возможности и **без** исправления бага | — |
| `docs` | только документация | — | | `docs` | только документация | — |
| `test` | тесты | — | | `test` | тесты | — |
| `ci` | CI/CD (`.gitea/`, workflows) | — | | `ci` | CI/CD (`.gitea/`, workflows); правки, из‑за которых нужны новые образы | patch |
| `chore` | обслуживание, deps, `.cursor/` | — | | `chore` | обслуживание, deps, `.cursor/` | — |
### Выбор type: semver, а не «красивые слова» ### Выбор type: semver, а не «красивые слова»
+1 -1
View File
@@ -12,7 +12,7 @@ Workflow: [workflows/ci.yaml](workflows/ci.yaml).
## CI (quality gates) ## CI (quality gates)
Job **changes** вычисляет флаги по путям в diff. Изменение `.gitea/workflows/*` поднимает полный прогон. Job **changes** вычисляет флаги по путям в diff. Полный прогон (все узлы openapi / web / go / bird2 в графе): `.gitea/workflows/*`, `scripts/*`, `.golangci.yml`, `.pre-commit-config.yaml`, корневой `package.json` / `.releaserc.json`. Отдельно: `migrations/*`, `docs/openapi.yaml``go` / `openapi` и т.д. (см. `ci.yaml`).
На **pull request****commitlint** (Conventional Commits). На **pull request****commitlint** (Conventional Commits).
+79 -39
View File
@@ -8,10 +8,9 @@ on:
jobs: jobs:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Гранулярная детекция изменений по модулям. # Детекция изменений по модулям (флаги → downstream-джобы в графе CI).
# Каждый флаг соответствует группе файлов; downstream-джобы запускаются # Полный прогон (все флаги true): .gitea/workflows/*, scripts/*, .golangci.yml,
# только когда их группа затронута. Изменение CI-конфигурации (.gitea/workflows/*) # .pre-commit-config.yaml — чтобы при правках CI/CD пересобирались все узлы.
# поднимает все флаги, чтобы гарантировать полный прогон.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
changes: changes:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -40,6 +39,23 @@ jobs:
docker_web=false docker_web=false
docker_bird=false docker_bird=false
# Все флаги true → openapi, web, go, bird2 (и release на main) в графе CI.
set_all_flags_true() {
openapi=true
go=true
web=true
bird_conf=true
docker_go=true
docker_web=true
docker_bird=true
}
write_outputs() {
for v in openapi go web bird_conf docker_go docker_web docker_bird; do
eval "echo \"\$v=\$$v\"" >> "$GITHUB_OUTPUT"
done
}
if [ "${{ github.event_name }}" = "pull_request" ]; then if [ "${{ github.event_name }}" = "pull_request" ]; then
base="${{ github.event.pull_request.base.sha }}" base="${{ github.event.pull_request.base.sha }}"
head="${{ github.event.pull_request.head.sha }}" head="${{ github.event.pull_request.head.sha }}"
@@ -52,62 +68,84 @@ jobs:
elif git rev-parse --verify HEAD~1 >/dev/null 2>&1; then elif git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
FILES="$(git diff --name-only HEAD~1 HEAD)" FILES="$(git diff --name-only HEAD~1 HEAD)"
else else
openapi=true; go=true; web=true; bird_conf=true set_all_flags_true
docker_go=true; docker_web=true; docker_bird=true write_outputs
for v in openapi go web bird_conf docker_go docker_web docker_bird; do echo "No parent commit — full pipeline (all modules)"
echo "$v=true" >> "$GITHUB_OUTPUT"
done
echo "No parent commit — full pipeline"
exit 0 exit 0
fi fi
fi fi
if [ -z "$(printf '%s' "$FILES" | tr -d '[:space:]')" ]; then if [ -z "$(printf '%s' "$FILES" | tr -d '[:space:]')" ]; then
go=true; web=true set_all_flags_true
for v in openapi go web bird_conf docker_go docker_web docker_bird; do write_outputs
eval "echo \"\$v=\$$v\"" >> "$GITHUB_OUTPUT" echo "Empty diff — full pipeline fallback"
done
echo "Empty diff — safe fallback: go=true web=true"
exit 0 exit 0
fi fi
ci_changed=false full_pipeline=false
while IFS= read -r f || [ -n "${f:-}" ]; do while IFS= read -r f || [ -n "${f:-}" ]; do
[ -z "${f:-}" ] && continue [ -z "${f:-}" ] && continue
case "$f" in case "$f" in
.gitea/workflows/*) ci_changed=true ;; # CI/CD инфраструктура — все узлы quality gates
docs/openapi.yaml|redocly.yaml) openapi=true ;; .gitea/workflows/*|.golangci.yml|.pre-commit-config.yaml|scripts/*)
web/README.md) ;; # doc-only full_pipeline=true
web/*) web=true ;; ;;
deploy/bird/*) bird_conf=true ;; docs/openapi.yaml|redocly.yaml)
deploy/docker/bird/*) docker_bird=true; docker_go=true ;; openapi=true
deploy/docker/gobinary/*) docker_go=true ;; ;;
deploy/docker/docker-bake.hcl) docker_go=true; docker_web=true ;; docs/api.md|docs/access.md)
deploy/docker/evobgp-agent/*) docker_go=true ;; openapi=true
deploy/docker/evobgp-web/*) docker_web=true ;; go=true
deploy/docker/bird2/*) docker_bird=true ;; ;;
go.mod|go.sum|go.work) go=true ;; web/README.md|web/components.json)
migrations/*) go=true ;; ;;
*.go) go=true ;; web/*)
cmd/*|internal/*) go=true ;; web=true
;;
deploy/bird/*)
bird_conf=true
go=true
;;
deploy/compose/*|deploy/docker/*)
docker_go=true
docker_web=true
docker_bird=true
go=true
;;
go.mod|go.sum|go.work)
go=true
;;
migrations/*)
go=true
;;
cmd/*|internal/*|*.go)
go=true
bird_conf=true
;;
docs/*)
go=true
;;
package.json|package-lock.json|.releaserc.json)
full_pipeline=true
;;
*)
go=true
;;
esac esac
done <<< "$FILES" done <<< "$FILES"
if $ci_changed; then if $full_pipeline; then
go=true; web=true; bird_conf=true set_all_flags_true
docker_go=true; docker_web=true; docker_bird=true
fi fi
for v in openapi go web bird_conf docker_go docker_web docker_bird; do write_outputs
eval "echo \"\$v=\$$v\"" >> "$GITHUB_OUTPUT"
done
echo "Changed files (first 30):" echo "Changed files (first 30):"
printf '%s\n' "$FILES" | head -n 30 printf '%s\n' "$FILES" | head -n 30
echo "--- flags ---" echo "--- flags ---"
echo "openapi=$openapi go=$go web=$web bird_conf=$bird_conf" echo "openapi=$openapi go=$go web=$web bird_conf=$bird_conf"
echo "docker_go=$docker_go docker_web=$docker_web docker_bird=$docker_bird ci=$ci_changed" echo "docker_go=$docker_go docker_web=$docker_web docker_bird=$docker_bird full_pipeline=$full_pipeline"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
openapi: openapi:
@@ -160,10 +198,12 @@ jobs:
run: sh scripts/lint-httpapi.sh run: sh scripts/lint-httpapi.sh
- name: Check migration pairs (DEP-03) - name: Check migration pairs (DEP-03)
run: sh scripts/check-migrations-pair.sh run: sh scripts/check-migrations-pair.sh
# go.mod: go 1.24 — бинарник golangci-lint < v1.64.2 (сборка на Go 1.23) не запускается.
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v6 uses: golangci/golangci-lint-action@v6
with: with:
version: v1.62 version: v1.64.8
install-mode: goinstall
- name: Test - name: Test
run: go test ./... -race -count=1 run: go test ./... -race -count=1
- name: Build all commands - name: Build all commands
+1
View File
@@ -2,6 +2,7 @@ run:
timeout: 5m timeout: 5m
linters: linters:
disable-all: true
enable: enable:
- gofmt - gofmt
- govet - govet
+1
View File
@@ -10,6 +10,7 @@
{ "type": "feat", "release": "minor" }, { "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" }, { "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" }, { "type": "perf", "release": "patch" },
{ "type": "ci", "release": "patch" },
{ "breaking": true, "release": "major" } { "breaking": true, "release": "major" }
] ]
} }
+4 -2
View File
@@ -7,9 +7,11 @@ EvoBGP использует [Conventional Commits](https://www.conventionalcommi
| Тип коммита | Bump | | Тип коммита | Bump |
|-------------|------| |-------------|------|
| `feat` | minor (1.0.0 → 1.1.0) | | `feat` | minor (1.0.0 → 1.1.0) |
| `fix`, `perf` | patch (1.0.0 → 1.0.1) | | `fix`, `perf`, `ci` | patch (1.5.1 → 1.5.2) |
| `feat!`, `fix!` или `BREAKING CHANGE:` в теле | major (1.0.0 → 2.0.0) | | `feat!`, `fix!` или `BREAKING CHANGE:` в теле | major (1.0.0 → 2.0.0) |
| `docs`, `chore`, `ci`, `test`, `refactor` | без релиза | | `docs`, `chore`, `test`, `refactor` | без релиза |
Отдельного суффикса `1.x.y.fix` в semver нет: «fix» в Conventional Commits означает **patch** (третья цифра). Для починки пайплайна без смены продукта — `fix(ci):` или `ci:` (оба дают patch после настройки `.releaserc.json`).
Первый релиз при отсутствии git-тегов — **1.0.0**, если есть releasable-коммиты. Первый релиз при отсутствии git-тегов — **1.0.0**, если есть releasable-коммиты.
+4 -4
View File
@@ -42,7 +42,7 @@ func AnnouncedPrefixes(ctx context.Context, hc *http.Client, asn int64) ([]netip
if err != nil { if err != nil {
return nil, fmt.Errorf("ripestat fetch AS%d: %w", asn, err) return nil, fmt.Errorf("ripestat fetch AS%d: %w", asn, err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 32<<20)) body, err := io.ReadAll(io.LimitReader(resp.Body, 32<<20))
if err != nil { if err != nil {
return nil, err return nil, err
@@ -52,8 +52,8 @@ func AnnouncedPrefixes(ctx context.Context, hc *http.Client, asn int64) ([]netip
} }
var wrap struct { var wrap struct {
Status string `json:"status"` Status string `json:"status"`
Data struct { Data struct {
Prefixes []struct { Prefixes []struct {
Prefix string `json:"prefix"` Prefix string `json:"prefix"`
} `json:"prefixes"` } `json:"prefixes"`
@@ -104,7 +104,7 @@ func ASHolderName(ctx context.Context, hc *http.Client, asn int64) (string, erro
if err != nil { if err != nil {
return "", fmt.Errorf("ripestat as-overview AS%d: %w", asn, err) return "", fmt.Errorf("ripestat as-overview AS%d: %w", asn, err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20)) body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))
if err != nil { if err != nil {
return "", err return "", err
+4 -4
View File
@@ -60,10 +60,10 @@ func RenderBGPTemplates(opts BGPTemplatesOptions) (string, error) {
// BGPPeerFromTemplateOptions describes protocol bgp NAME from TEMPLATE { … }. // BGPPeerFromTemplateOptions describes protocol bgp NAME from TEMPLATE { … }.
type BGPPeerFromTemplateOptions struct { type BGPPeerFromTemplateOptions struct {
ProtocolName string ProtocolName string
TemplateName string TemplateName string
NeighborIP string NeighborIP string
NeighborASN uint32 NeighborASN uint32
// If set, emits "local … as …" before neighbor (overrides template local/ASN for this peer). // If set, emits "local … as …" before neighbor (overrides template local/ASN for this peer).
OverrideLocalIP string OverrideLocalIP string
OverrideLocalASN uint32 OverrideLocalASN uint32
+6 -6
View File
@@ -17,12 +17,12 @@ import (
// Manifest describes bundle contents for evobgp-node verification. // Manifest describes bundle contents for evobgp-node verification.
type Manifest struct { type Manifest struct {
RevisionID string `json:"revision_id"` RevisionID string `json:"revision_id"`
SpeakerID string `json:"speaker_id,omitempty"` SpeakerID string `json:"speaker_id,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Files []FileEntry `json:"files"` Files []FileEntry `json:"files"`
Algorithm string `json:"signature_algorithm"` Algorithm string `json:"signature_algorithm"`
PublicKeyB64 string `json:"public_key_base64"` PublicKeyB64 string `json:"public_key_base64"`
} }
// FileEntry is one file inside the bundle archive. // FileEntry is one file inside the bundle archive.
+1 -1
View File
@@ -27,7 +27,7 @@ func VerifyGzippedTar(bundle []byte, pub ed25519.PublicKey) (*VerifiedContents,
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer gr.Close() defer func() { _ = gr.Close() }()
var manifestRaw []byte var manifestRaw []byte
var sig []byte var sig []byte
+11 -11
View File
@@ -7,21 +7,21 @@ import (
) )
const ( const (
internalErrorDetail = "an internal error occurred" internalErrorDetail = "an internal error occurred"
badGatewayDetail = "upstream request failed" badGatewayDetail = "upstream request failed"
notFoundDetail = "resource not found" notFoundDetail = "resource not found"
invalidInputDetail = "invalid request data" invalidInputDetail = "invalid request data"
cdnExtractDetail = "could not extract prefixes from source" cdnExtractDetail = "could not extract prefixes from source"
csvInvalidRowDetail = "invalid row in csv file" csvInvalidRowDetail = "invalid row in csv file"
) )
// Problem is RFC 9457 application/problem+json. // Problem is RFC 9457 application/problem+json.
type Problem struct { type Problem struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Title string `json:"title"` Title string `json:"title"`
Status int `json:"status"` Status int `json:"status"`
Detail string `json:"detail,omitempty"` Detail string `json:"detail,omitempty"`
Instance string `json:"instance,omitempty"` Instance string `json:"instance,omitempty"`
} }
func writeProblem(w http.ResponseWriter, status int, title, detail string) { func writeProblem(w http.ResponseWriter, status int, title, detail string) {
+1 -1
View File
@@ -258,7 +258,7 @@ func (s *Server) handlePreviewCDNSource(w http.ResponseWriter, r *http.Request)
writeBadGateway(w, "cdn preview fetch", err) writeBadGateway(w, "cdn preview fetch", err)
return return
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
_, _ = io.Copy(io.Discard, resp.Body) _, _ = io.Copy(io.Discard, resp.Body)
writeBadGateway(w, "cdn preview fetch", fmt.Errorf("upstream status: %s", resp.Status)) writeBadGateway(w, "cdn preview fetch", fmt.Errorf("upstream status: %s", resp.Status))
+3 -3
View File
@@ -34,7 +34,7 @@ func TestModuleEntriesCSVImportExportIPRanges(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer respList.Body.Close() defer func() { _ = respList.Body.Close() }()
if respList.StatusCode != http.StatusOK { if respList.StatusCode != http.StatusOK {
b, _ := io.ReadAll(respList.Body) b, _ := io.ReadAll(respList.Body)
t.Fatalf("communities status %d: %s", respList.StatusCode, b) t.Fatalf("communities status %d: %s", respList.StatusCode, b)
@@ -59,7 +59,7 @@ func TestModuleEntriesCSVImportExportIPRanges(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer respImport.Body.Close() defer func() { _ = respImport.Body.Close() }()
if respImport.StatusCode != http.StatusOK { if respImport.StatusCode != http.StatusOK {
b, _ := io.ReadAll(respImport.Body) b, _ := io.ReadAll(respImport.Body)
t.Fatalf("import status %d: %s", respImport.StatusCode, b) t.Fatalf("import status %d: %s", respImport.StatusCode, b)
@@ -80,7 +80,7 @@ func TestModuleEntriesCSVImportExportIPRanges(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer respExport.Body.Close() defer func() { _ = respExport.Body.Close() }()
if respExport.StatusCode != http.StatusOK { if respExport.StatusCode != http.StatusOK {
b, _ := io.ReadAll(respExport.Body) b, _ := io.ReadAll(respExport.Body)
t.Fatalf("export status %d: %s", respExport.StatusCode, b) t.Fatalf("export status %d: %s", respExport.StatusCode, b)
+3 -3
View File
@@ -35,7 +35,7 @@ func TestNestedModuleListPagination(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
_, _ = io.Copy(io.Discard, resp.Body) _, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close() _ = resp.Body.Close()
if resp.StatusCode != http.StatusCreated { if resp.StatusCode != http.StatusCreated {
t.Fatalf("create entry %d: status %d", i, resp.StatusCode) t.Fatalf("create entry %d: status %d", i, resp.StatusCode)
} }
@@ -47,7 +47,7 @@ func TestNestedModuleListPagination(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("list status %d: %s", resp.StatusCode, b) t.Fatalf("list status %d: %s", resp.StatusCode, b)
@@ -73,7 +73,7 @@ func TestNestedModuleListPagination(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp2.Body.Close() defer func() { _ = resp2.Body.Close() }()
var page2 struct { var page2 struct {
Items []map[string]any `json:"items"` Items []map[string]any `json:"items"`
HasMore bool `json:"has_more"` HasMore bool `json:"has_more"`
+4 -4
View File
@@ -32,10 +32,10 @@ type Server struct {
type Options struct { type Options struct {
APIKeys string APIKeys string
// DatabaseURL enables PostgreSQL-backed store (migrations applied on connect). // DatabaseURL enables PostgreSQL-backed store (migrations applied on connect).
DatabaseURL string DatabaseURL string
InsecureDev bool InsecureDev bool
SeedDemo bool SeedDemo bool
BundleSeedHex string BundleSeedHex string
CORSAllowedOrigins string CORSAllowedOrigins string
} }
+14 -14
View File
@@ -51,7 +51,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -76,7 +76,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusAccepted {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -97,7 +97,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusAccepted {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -118,7 +118,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -132,7 +132,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -162,7 +162,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
resp.Body.Close() _ = resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
t.Fatalf("%s status %d: %s", path, resp.StatusCode, b) t.Fatalf("%s status %d: %s", path, resp.StatusCode, b)
} }
@@ -185,7 +185,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -215,7 +215,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -255,7 +255,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusForbidden { if resp.StatusCode != http.StatusForbidden {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d want 403: %s", resp.StatusCode, b) t.Fatalf("status %d want 403: %s", resp.StatusCode, b)
@@ -269,7 +269,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusAccepted {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -289,7 +289,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusAccepted { if resp.StatusCode != http.StatusAccepted {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -314,7 +314,7 @@ func TestAPIRefreshApplyJobsBundle(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
@@ -341,7 +341,7 @@ func waitJob(t *testing.T, client *http.Client, base, token, jobID string) {
t.Fatal(err) t.Fatal(err)
} }
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
resp.Body.Close() _ = resp.Body.Close()
var body struct { var body struct {
Status string `json:"status"` Status string `json:"status"`
} }
@@ -405,7 +405,7 @@ func TestVersionEndpoints(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
t.Fatalf("status %d: %s", resp.StatusCode, b) t.Fatalf("status %d: %s", resp.StatusCode, b)
+2 -2
View File
@@ -66,7 +66,7 @@ func fetchLatestRevision(base, token, speaker string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("latest revision: %s: %s", resp.Status, strings.TrimSpace(string(b))) return "", fmt.Errorf("latest revision: %s: %s", resp.Status, strings.TrimSpace(string(b)))
@@ -94,7 +94,7 @@ func fetchBundle(base, token, speaker, revision string) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("bundle: %s: %s", resp.Status, strings.TrimSpace(string(b))) return nil, fmt.Errorf("bundle: %s: %s", resp.Status, strings.TrimSpace(string(b)))
+1 -1
View File
@@ -27,7 +27,7 @@ func Run(args []string) int {
// Usage prints CLI help to w. // Usage prints CLI help to w.
func Usage(w interface{ Write([]byte) (int, error) }) { func Usage(w interface{ Write([]byte) (int, error) }) {
fmt.Fprintf(w, `Usage: _, _ = fmt.Fprintf(w, `Usage:
evobgp-node pull-bundle -base-url URL -token TOKEN -speaker-id ID [-revision-id ID] [-o path] evobgp-node pull-bundle -base-url URL -token TOKEN -speaker-id ID [-revision-id ID] [-o path]
evobgp-node verify-bundle -f bundle.tar.gz (-pubkey-base64 B64 | -pubkey-hex HEX) evobgp-node verify-bundle -f bundle.tar.gz (-pubkey-base64 B64 | -pubkey-hex HEX)
evobgp-node apply-bundle -f bundle.tar.gz -extract-dir DIR (-pubkey-base64 B64 | -pubkey-hex HEX) evobgp-node apply-bundle -f bundle.tar.gz -extract-dir DIR (-pubkey-base64 B64 | -pubkey-hex HEX)
+1 -1
View File
@@ -126,7 +126,7 @@ func applyCDNSourceHTTPResult(ctx context.Context, st store.Backend, hc *http.Cl
return nil, fmt.Errorf("cdn url %s: 304 without cached prefixes", u) return nil, fmt.Errorf("cdn url %s: 304 without cached prefixes", u)
} }
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
_, _ = io.Copy(io.Discard, resp.Body) _, _ = io.Copy(io.Discard, resp.Body)
@@ -46,4 +46,3 @@ func TestBuildPreviewFragments_SamePrefixDifferentCommunity(t *testing.T) {
t.Fatalf("expected deterministic static preview text, got first:\n%s\nsecond:\n%s", staticV4, staticV4Second) t.Fatalf("expected deterministic static preview text, got first:\n%s\nsecond:\n%s", staticV4, staticV4Second)
} }
} }
+10 -10
View File
@@ -306,7 +306,7 @@ func resolveDomainWithDOHMessage(ctx context.Context, hc *http.Client, baseURL,
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return nil, fmt.Errorf("doh dns-message status %s: %s", resp.Status, strings.TrimSpace(string(body))) return nil, fmt.Errorf("doh dns-message status %s: %s", resp.Status, strings.TrimSpace(string(body)))
@@ -378,7 +378,7 @@ func resolveDomainWithDOHJSON(ctx context.Context, hc *http.Client, baseURL, hos
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return nil, fmt.Errorf("doh status %s: %s", resp.Status, strings.TrimSpace(string(body))) return nil, fmt.Errorf("doh status %s: %s", resp.Status, strings.TrimSpace(string(body)))
@@ -725,15 +725,15 @@ func dedupeSortedPrefixLines(rows []store.PrefixRow) []prefixHashLine {
} }
func writePrefixLinesHash(h interface{ Write([]byte) (int, error) }, tenantID string, lines []prefixHashLine) { func writePrefixLinesHash(h interface{ Write([]byte) (int, error) }, tenantID string, lines []prefixHashLine) {
h.Write([]byte(strings.TrimSpace(tenantID))) _, _ = h.Write([]byte(strings.TrimSpace(tenantID)))
h.Write([]byte{0}) _, _ = h.Write([]byte{0})
for _, l := range lines { for _, l := range lines {
h.Write([]byte(l.p)) _, _ = h.Write([]byte(l.p))
h.Write([]byte{1}) _, _ = h.Write([]byte{1})
h.Write([]byte(l.c)) _, _ = h.Write([]byte(l.c))
h.Write([]byte{1}) _, _ = h.Write([]byte{1})
h.Write([]byte(l.s)) _, _ = h.Write([]byte(l.s))
h.Write([]byte{0}) _, _ = h.Write([]byte{0})
} }
} }
+1 -1
View File
@@ -28,7 +28,7 @@ func agentDebugNDJSON3214(hypothesisID, location, message string, data map[strin
if err != nil { if err != nil {
return return
} }
defer f.Close() defer func() { _ = f.Close() }()
var ms runtime.MemStats var ms runtime.MemStats
runtime.ReadMemStats(&ms) runtime.ReadMemStats(&ms)
payload := map[string]any{ payload := map[string]any{
+1 -1
View File
@@ -121,7 +121,7 @@ func postTenantRefresh(ctx context.Context, deps *Deps, moduleIDs []string, idem
if err != nil { if err != nil {
return err return err
} }
defer resp.Body.Close() defer func() { _ = resp.Body.Close() }()
if resp.StatusCode == http.StatusNoContent || resp.StatusCode == http.StatusAccepted { if resp.StatusCode == http.StatusNoContent || resp.StatusCode == http.StatusAccepted {
return nil return nil
} }
+7 -7
View File
@@ -33,13 +33,13 @@ type Memory struct {
peers map[string]*BGPPeer peers map[string]*BGPPeer
dohProfiles map[string]*DohProfile dohProfiles map[string]*DohProfile
communities map[string]*Community communities map[string]*Community
cdnSources map[string]*CDNSource cdnSources map[string]*CDNSource
asEntries map[string]*ASEntry asEntries map[string]*ASEntry
domainEnt map[string]*DomainEntry domainEnt map[string]*DomainEntry
ipRanges map[string]*IPRangeEntry ipRanges map[string]*IPRangeEntry
settings map[string]map[string]any // tenantID -> key -> JSON-compatible value settings map[string]map[string]any // tenantID -> key -> JSON-compatible value
revPrefixes map[string][]PrefixRow revPrefixes map[string][]PrefixRow
moduleSnapshots map[string]*moduleSnapshotRec moduleSnapshots map[string]*moduleSnapshotRec
asnPrefixCache map[int64]*ASNPrefixCacheEntry asnPrefixCache map[int64]*ASNPrefixCacheEntry
+3 -3
View File
@@ -19,9 +19,9 @@ func TestEffectivePeerEnabledOnCreate(t *testing.T) {
func TestParsePeerNeighbor(t *testing.T) { func TestParsePeerNeighbor(t *testing.T) {
tests := []struct { tests := []struct {
in string in string
want string want string
wantOK bool wantOK bool
}{ }{
{"192.168.0.2", "192.168.0.2", true}, {"192.168.0.2", "192.168.0.2", true},
{"192.168.0.2/32", "192.168.0.2", true}, {"192.168.0.2/32", "192.168.0.2", true},