From 3d67d9141ca08dc030302f3c254f4268248c430b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 13 Nov 2025 21:56:29 +0400 Subject: [PATCH 1/2] fix: allocate partition size for gaps We don't need to align highLBA (or the end of the next partition), as otherwise we can't drop and re-create the partition in the same place. Signed-off-by: Andrey Smirnov --- blkid/blkid_linux_test.go | 2 +- partitioning/gpt/gpt.go | 4 +-- partitioning/gpt/gpt_test.go | 33 ++++++++++++++++++++ partitioning/gpt/testdata/smalldelete.gdisk | 20 ++++++++++++ partitioning/gpt/testdata/smalldelete.sfdisk | 10 ++++++ 5 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 partitioning/gpt/testdata/smalldelete.gdisk create mode 100644 partitioning/gpt/testdata/smalldelete.sfdisk diff --git a/blkid/blkid_linux_test.go b/blkid/blkid_linux_test.go index d06a37e..f0c24d0 100644 --- a/blkid/blkid_linux_test.go +++ b/blkid/blkid_linux_test.go @@ -487,7 +487,7 @@ func TestProbePathFilesystems(t *testing.T) { expectedBlockSize: []uint32{0x20000}, expectedFSBlockSize: []uint32{0x20000}, - expectedFSSize: 0x100554, + expectedFSSize: 0x1005e8, expectedSignatures: []blkid.SignatureRange{ {Offset: 0, Size: 4}, }, diff --git a/partitioning/gpt/gpt.go b/partitioning/gpt/gpt.go index 75be94b..c4dc480 100644 --- a/partitioning/gpt/gpt.go +++ b/partitioning/gpt/gpt.go @@ -338,17 +338,17 @@ func (t *Table) allocatableRanges() []allocatableRange { highLBA = t.entries[partitionIdx].FirstLBA - 1 } else { highLBA = t.lastUsableLBA + highLBA = highLBA/t.alignment*t.alignment - 1 } lowLBA = (lowLBA + t.alignment - 1) / t.alignment * t.alignment - highLBA = highLBA / t.alignment * t.alignment if highLBA > lowLBA { ranges = append(ranges, allocatableRange{ lowLBA: lowLBA, highLBA: highLBA, partitionIdx: partitionIdx, - size: (highLBA - lowLBA) * uint64(t.sectorSize), + size: (highLBA - lowLBA + 1) * uint64(t.sectorSize), }) } diff --git a/partitioning/gpt/gpt_test.go b/partitioning/gpt/gpt_test.go index 56aa823..75f86fa 100644 --- a/partitioning/gpt/gpt_test.go +++ b/partitioning/gpt/gpt_test.go @@ -156,6 +156,39 @@ func TestGPT(t *testing.T) { expectedSfdiskDump: loadTestdata(t, "allocate.sfdisk"), expectedGdiskDump: loadTestdata(t, "allocate.gdisk"), }, + { + name: "allocate with small delete", + diskSize: 4 * GiB, + opts: []gpt.Option{ + gpt.WithDiskGUID(uuid.MustParse("B6D003E5-7D1D-45E3-9F4B-4A2430B46D4A")), + }, + allocator: func(t *testing.T, table *gpt.Table) { + t.Helper() + + assertAllocated(t, 1)(table.AllocatePartition(1*GiB, "1G", partType1, + gpt.WithUniqueGUID(uuid.MustParse("DA66737E-1ED4-4DDF-B98C-70CEBFE3ADA0")), + )) + assertAllocated(t, 2)(table.AllocatePartition(100*MiB, "100M", partType1, + gpt.WithUniqueGUID(uuid.MustParse("3D0FE86B-7791-4659-B564-FC49A542866D")), + gpt.WithLegacyBIOSBootableAttribute(true), + )) + assertAllocated(t, 3)(table.AllocatePartition( + table.LargestContiguousAllocatable(), "2.5G", partType2, + gpt.WithUniqueGUID(uuid.MustParse("EE1A711E-DE12-4D9F-98FF-672F7AD638F8")), + )) + + require.NoError(t, table.DeletePartition(1)) + + assert.EqualValues(t, 100*MiB, table.LargestContiguousAllocatable()) + + assertAllocated(t, 2)(table.AllocatePartition(100*MiB, "100M", partType2, + gpt.WithUniqueGUID(uuid.MustParse("15E609C8-9775-4E86-AF59-8A87E7C03FAB")), + )) + }, + + expectedSfdiskDump: loadTestdata(t, "smalldelete.sfdisk"), + expectedGdiskDump: loadTestdata(t, "smalldelete.gdisk"), + }, { name: "allocate with deletes", diskSize: 6 * GiB, diff --git a/partitioning/gpt/testdata/smalldelete.gdisk b/partitioning/gpt/testdata/smalldelete.gdisk new file mode 100644 index 0000000..440f169 --- /dev/null +++ b/partitioning/gpt/testdata/smalldelete.gdisk @@ -0,0 +1,20 @@ +Partition table scan: + MBR: protective + BSD: not present + APM: not present + GPT: present + +Found valid GPT with protective MBR; using GPT. + 8388608 sectors, 4.0 GiB +Sector size (logical/physical): 512/512 bytes +Disk identifier (GUID): B6D003E5-7D1D-45E3-9F4B-4A2430B46D4A +Partition table holds up to 128 entries +Main partition table begins at sector 2 and ends at sector 33 +First usable sector is 2048, last usable sector is 8388574 +Partitions will be aligned on 2048-sector boundaries +Total free space is 2015 sectors (1007.5 KiB) + +Number Start (sector) End (sector) Size Code Name + 1 2048 2099199 1024.0 MiB EF00 1G + 2 2099200 2303999 100.0 MiB 8E00 100M + 3 2304000 8386559 2.9 GiB 8E00 2.5G diff --git a/partitioning/gpt/testdata/smalldelete.sfdisk b/partitioning/gpt/testdata/smalldelete.sfdisk new file mode 100644 index 0000000..a157935 --- /dev/null +++ b/partitioning/gpt/testdata/smalldelete.sfdisk @@ -0,0 +1,10 @@ +label: gpt +label-id: B6D003E5-7D1D-45E3-9F4B-4A2430B46D4A +unit: sectors +first-lba: 2048 +last-lba: 8388574 +sector-size: 512 + +start= 2048, size= 2097152, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=DA66737E-1ED4-4DDF-B98C-70CEBFE3ADA0, name="1G" +start= 2099200, size= 204800, type=E6D6D379-F507-44C2-A23C-238F2A3DF928, uuid=15E609C8-9775-4E86-AF59-8A87E7C03FAB, name="100M" +start= 2304000, size= 6082560, type=E6D6D379-F507-44C2-A23C-238F2A3DF928, uuid=EE1A711E-DE12-4D9F-98FF-672F7AD638F8, name="2.5G" From 12166934181db286d7c8d389275b2c0154c3c143 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 13 Nov 2025 22:02:10 +0400 Subject: [PATCH 2/2] chore: rekres and update linter issues Fix linting issues. Signed-off-by: Andrey Smirnov --- .conform.yaml | 4 +- .dockerignore | 3 +- .github/workflows/ci.yaml | 124 +++++++++++++++--- .../workflows/slack-notify-ci-failure.yaml | 88 +++++++++++++ .github/workflows/slack-notify.yaml | 57 ++++---- .github/workflows/stale.yml | 4 +- Dockerfile | 25 +++- Makefile | 28 ++-- blkid/blkid_linux_test.go | 28 ++-- block/device_linux_test.go | 4 +- encryption/luks/luks.go | 3 + encryption/luks/luks_test.go | 2 +- encryption/luks/options.go | 1 - hack/govulncheck.sh | 86 ++++++++++++ partitioning/gpt/gpt_test.go | 5 +- 15 files changed, 374 insertions(+), 88 deletions(-) create mode 100644 .github/workflows/slack-notify-ci-failure.yaml create mode 100644 hack/govulncheck.sh diff --git a/.conform.yaml b/.conform.yaml index cde6d97..b557351 100644 --- a/.conform.yaml +++ b/.conform.yaml @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2024-02-29T11:53:44Z by kres latest. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. policies: - type: commit @@ -12,7 +12,7 @@ policies: gitHubOrganization: siderolabs spellcheck: locale: US - maximumOfOneCommit: true + maximumOfOneCommit: false header: length: 89 imperative: true diff --git a/.dockerignore b/.dockerignore index fa8df8c..69e49d1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-05-22T16:02:51Z by kres 9f64b0d. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. * !internal @@ -14,3 +14,4 @@ !.golangci.yml !CHANGELOG.md !.markdownlint.json +!hack/govulncheck.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dc553dd..65a9155 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-07-28T16:44:46Z by kres 1f18c2e. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. concurrency: group: ${{ github.head_ref || github.run_id }} @@ -26,13 +26,12 @@ jobs: packages: write pull-requests: read runs-on: - - self-hosted - - generic + group: generic if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) steps: - name: gather-system-info id: system-info - uses: kenchan0130/actions-system-info@v1.3.1 + uses: kenchan0130/actions-system-info@v1.4.0 continue-on-error: true - name: print-system-info run: | @@ -56,7 +55,7 @@ jobs: done continue-on-error: true - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Unshallow run: | git fetch --prune --unshallow @@ -70,6 +69,107 @@ jobs: - name: base run: | make base + - name: release-notes + if: startsWith(github.ref, 'refs/tags/') + run: | + make release-notes + - name: Release + if: startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v2 + with: + body_path: _out/RELEASE_NOTES.md + draft: "true" + lint: + runs-on: + group: generic + if: github.event_name == 'pull_request' + needs: + - default + steps: + - name: gather-system-info + id: system-info + uses: kenchan0130/actions-system-info@v1.4.0 + continue-on-error: true + - name: print-system-info + run: | + MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024)) + + OUTPUTS=( + "CPU Core: ${{ steps.system-info.outputs.cpu-core }}" + "CPU Model: ${{ steps.system-info.outputs.cpu-model }}" + "Hostname: ${{ steps.system-info.outputs.hostname }}" + "NodeName: ${NODE_NAME}" + "Kernel release: ${{ steps.system-info.outputs.kernel-release }}" + "Kernel version: ${{ steps.system-info.outputs.kernel-version }}" + "Name: ${{ steps.system-info.outputs.name }}" + "Platform: ${{ steps.system-info.outputs.platform }}" + "Release: ${{ steps.system-info.outputs.release }}" + "Total memory: ${MEMORY_GB} GB" + ) + + for OUTPUT in "${OUTPUTS[@]}";do + echo "${OUTPUT}" + done + continue-on-error: true + - name: checkout + uses: actions/checkout@v5 + - name: Unshallow + run: | + git fetch --prune --unshallow + - name: Set up Docker Buildx + id: setup-buildx + uses: docker/setup-buildx-action@v3 + with: + driver: remote + endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234 + timeout-minutes: 10 + - name: lint + run: | + make lint + unit-tests: + runs-on: + group: generic + if: github.event_name == 'pull_request' + needs: + - default + steps: + - name: gather-system-info + id: system-info + uses: kenchan0130/actions-system-info@v1.4.0 + continue-on-error: true + - name: print-system-info + run: | + MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024)) + + OUTPUTS=( + "CPU Core: ${{ steps.system-info.outputs.cpu-core }}" + "CPU Model: ${{ steps.system-info.outputs.cpu-model }}" + "Hostname: ${{ steps.system-info.outputs.hostname }}" + "NodeName: ${NODE_NAME}" + "Kernel release: ${{ steps.system-info.outputs.kernel-release }}" + "Kernel version: ${{ steps.system-info.outputs.kernel-version }}" + "Name: ${{ steps.system-info.outputs.name }}" + "Platform: ${{ steps.system-info.outputs.platform }}" + "Release: ${{ steps.system-info.outputs.release }}" + "Total memory: ${MEMORY_GB} GB" + ) + + for OUTPUT in "${OUTPUTS[@]}";do + echo "${OUTPUT}" + done + continue-on-error: true + - name: checkout + uses: actions/checkout@v5 + - name: Unshallow + run: | + git fetch --prune --unshallow + - name: Set up Docker Buildx + id: setup-buildx + uses: docker/setup-buildx-action@v3 + with: + driver: remote + endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234 + timeout-minutes: 10 - name: unit-tests run: | make unit-tests @@ -80,18 +180,6 @@ jobs: uses: codecov/codecov-action@v5 with: files: _out/coverage-unit-tests.txt + flags: unit-tests token: ${{ secrets.CODECOV_TOKEN }} timeout-minutes: 3 - - name: lint - run: | - make lint - - name: release-notes - if: startsWith(github.ref, 'refs/tags/') - run: | - make release-notes - - name: Release - if: startsWith(github.ref, 'refs/tags/') - uses: crazy-max/ghaction-github-release@v2 - with: - body_path: _out/RELEASE_NOTES.md - draft: "true" diff --git a/.github/workflows/slack-notify-ci-failure.yaml b/.github/workflows/slack-notify-ci-failure.yaml new file mode 100644 index 0000000..e20d17f --- /dev/null +++ b/.github/workflows/slack-notify-ci-failure.yaml @@ -0,0 +1,88 @@ +# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. +# +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. + +"on": + workflow_run: + workflows: + - default + types: + - completed + branches: + - v2 +name: slack-notify-failure +jobs: + slack-notify: + runs-on: + group: generic + if: github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event != 'pull_request' + steps: + - name: Slack Notify + uses: slackapi/slack-github-action@v2 + with: + method: chat.postMessage + payload: | + { + "channel": "ci-failure", + "text": "${{ github.event.workflow_run.conclusion }} - ${{ github.repository }}", + "icon_emoji": "${{ github.event.workflow_run.conclusion == 'success' && ':white_check_mark:' || github.event.workflow_run.conclusion == 'failure' && ':x:' || ':warning:' }}", + "username": "GitHub Actions", + "attachments": [ + { + "blocks": [ + { + "fields": [ + { + "text": "${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}", + "type": "mrkdwn" + }, + { + "text": "*Status:*\n`${{ github.event.workflow_run.conclusion }}`", + "type": "mrkdwn" + } + ], + "type": "section" + }, + { + "fields": [ + { + "text": "*Author:*\n`${{ github.actor }}`", + "type": "mrkdwn" + }, + { + "text": "*Event:*\n`${{ github.event.workflow_run.event }}`", + "type": "mrkdwn" + } + ], + "type": "section" + }, + { + "type": "divider" + }, + { + "elements": [ + { + "text": { + "text": "Logs", + "type": "plain_text" + }, + "type": "button", + "url": "${{ github.event.workflow_run.html_url }}" + }, + { + "text": { + "text": "Commit", + "type": "plain_text" + }, + "type": "button", + "url": "${{ github.event.repository.html_url }}/commit/${{ github.sha }}" + } + ], + "type": "actions" + } + ], + "color": "${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}" + } + ] + } + token: ${{ secrets.SLACK_BOT_TOKEN_V2 }} diff --git a/.github/workflows/slack-notify.yaml b/.github/workflows/slack-notify.yaml index e5e83ba..bd2247d 100644 --- a/.github/workflows/slack-notify.yaml +++ b/.github/workflows/slack-notify.yaml @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-07-28T16:44:46Z by kres 1f18c2e. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. "on": workflow_run: @@ -12,8 +12,7 @@ name: slack-notify jobs: slack-notify: runs-on: - - self-hosted - - generic + group: generic if: github.event.workflow_run.conclusion != 'skipped' steps: - name: Get PR number @@ -29,64 +28,66 @@ jobs: method: chat.postMessage payload: | { - "channel": "proj-talos-maintainers", + "channel": "ci-all", + "text": "${{ github.event.workflow_run.conclusion }} - ${{ github.repository }}", + "icon_emoji": "${{ github.event.workflow_run.conclusion == 'success' && ':white_check_mark:' || github.event.workflow_run.conclusion == 'failure' && ':x:' || ':warning:' }}", + "username": "GitHub Actions", "attachments": [ { - "color": "${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}", - "fallback": "test", "blocks": [ { - "type": "section", "fields": [ { - "type": "mrkdwn", - "text": "${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}" + "text": "${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}", + "type": "mrkdwn" }, { - "type": "mrkdwn", - "text": "*Status:*\n`${{ github.event.workflow_run.conclusion }}`" + "text": "*Status:*\n`${{ github.event.workflow_run.conclusion }}`", + "type": "mrkdwn" } - ] + ], + "type": "section" }, { - "type": "section", "fields": [ { - "type": "mrkdwn", - "text": "*Author:*\n`${{ github.actor }}`" + "text": "*Author:*\n`${{ github.actor }}`", + "type": "mrkdwn" }, { - "type": "mrkdwn", - "text": "*Event:*\n`${{ github.event.workflow_run.event }}`" + "text": "*Event:*\n`${{ github.event.workflow_run.event }}`", + "type": "mrkdwn" } - ] + ], + "type": "section" }, { "type": "divider" }, { - "type": "actions", "elements": [ { - "type": "button", "text": { - "type": "plain_text", - "text": "Logs" + "text": "Logs", + "type": "plain_text" }, + "type": "button", "url": "${{ github.event.workflow_run.html_url }}" }, { - "type": "button", "text": { - "type": "plain_text", - "text": "Commit" + "text": "Commit", + "type": "plain_text" }, + "type": "button", "url": "${{ github.event.repository.html_url }}/commit/${{ github.sha }}" } - ] + ], + "type": "actions" } - ] + ], + "color": "${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}" } ] } - token: ${{ secrets.SLACK_BOT_TOKEN }} + token: ${{ secrets.SLACK_BOT_TOKEN_V2 }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 9118bd9..1eac3c4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-07-28T16:44:46Z by kres 1f18c2e. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. "on": schedule: @@ -15,7 +15,7 @@ jobs: - ubuntu-latest steps: - name: Close stale issues and PRs - uses: actions/stale@v9.1.0 + uses: actions/stale@v10.1.0 with: close-issue-message: This issue was closed because it has been stalled for 7 days with no activity. days-before-issue-close: "5" diff --git a/Dockerfile b/Dockerfile index a434b79..f10de57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,16 @@ -# syntax = docker/dockerfile-upstream:1.17.1-labs +# syntax = docker/dockerfile-upstream:1.19.0-labs # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-07-28T16:44:46Z by kres 1f18c2e. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. -ARG TOOLCHAIN +ARG TOOLCHAIN=scratch # cleaned up specs and compiled versions FROM scratch AS generate # runs markdownlint -FROM docker.io/oven/bun:1.2.18-alpine AS lint-markdown +FROM docker.io/oven/bun:1.3.1-alpine AS lint-markdown WORKDIR /src RUN bun i markdownlint-cli@0.45.0 sentences-per-line@0.3.0 COPY .markdownlint.json . @@ -19,7 +19,7 @@ RUN bunx markdownlint --ignore "CHANGELOG.md" --ignore "**/node_modules/**" --ig # base toolchain image FROM --platform=${BUILDPLATFORM} ${TOOLCHAIN} AS toolchain -RUN apk --update --no-cache add bash curl build-base protoc protobuf-dev cdrkit cryptsetup dosfstools e2fsprogs gptfdisk lvm2 parted util-linux squashfs-tools xfsprogs +RUN apk --update --no-cache add bash build-base curl jq protoc protobuf-dev cdrkit cryptsetup dosfstools e2fsprogs gptfdisk lvm2 parted util-linux squashfs-tools xfsprogs # Creates the ZFS image FROM fedora:39 AS zfs-img-gen @@ -84,10 +84,19 @@ COPY .golangci.yml . ENV GOGC=50 RUN --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/root/.cache/golangci-lint,id=go-blockdevice/root/.cache/golangci-lint,sharing=locked --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg golangci-lint run --config .golangci.yml +# runs golangci-lint fmt +FROM base AS lint-golangci-lint-fmt-run +WORKDIR /src +COPY .golangci.yml . +ENV GOGC=50 +RUN --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/root/.cache/golangci-lint,id=go-blockdevice/root/.cache/golangci-lint,sharing=locked --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg golangci-lint fmt --config .golangci.yml +RUN --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/root/.cache/golangci-lint,id=go-blockdevice/root/.cache/golangci-lint,sharing=locked --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg golangci-lint run --fix --issues-exit-code 0 --config .golangci.yml + # runs govulncheck FROM base AS lint-govulncheck WORKDIR /src -RUN --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg govulncheck ./... +COPY --chmod=0755 hack/govulncheck.sh ./hack/govulncheck.sh +RUN --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg ./hack/govulncheck.sh ./... # runs unit-tests with race detector FROM base AS unit-tests-race @@ -103,6 +112,10 @@ WORKDIR /src ARG TESTPKGS RUN --security=insecure --mount=type=cache,target=/root/.cache/go-build,id=go-blockdevice/root/.cache/go-build --mount=type=cache,target=/go/pkg,id=go-blockdevice/go/pkg --mount=type=cache,target=/tmp,id=go-blockdevice/tmp go test -covermode=atomic -coverprofile=coverage.txt -coverpkg=${TESTPKGS} ${TESTPKGS} +# clean golangci-lint fmt output +FROM scratch AS lint-golangci-lint-fmt +COPY --from=lint-golangci-lint-fmt-run /src . + FROM scratch AS unit-tests COPY --from=unit-tests-run /src/coverage.txt /coverage-unit-tests.txt diff --git a/Makefile b/Makefile index 141276b..76dcd53 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT. # -# Generated on 2025-07-28T16:44:46Z by kres 1f18c2e. +# Generated on 2025-11-13T17:57:11Z by kres e1d6dac. # common variables @@ -17,21 +17,21 @@ WITH_RACE ?= false REGISTRY ?= ghcr.io USERNAME ?= siderolabs REGISTRY_AND_USERNAME ?= $(REGISTRY)/$(USERNAME) -PROTOBUF_GO_VERSION ?= 1.36.6 +PROTOBUF_GO_VERSION ?= 1.36.10 GRPC_GO_VERSION ?= 1.5.1 -GRPC_GATEWAY_VERSION ?= 2.27.1 +GRPC_GATEWAY_VERSION ?= 2.27.3 VTPROTOBUF_VERSION ?= 0.6.0 -GOIMPORTS_VERSION ?= 0.34.0 -GOMOCK_VERSION ?= 0.5.2 -DEEPCOPY_VERSION ?= v0.5.6 -GOLANGCILINT_VERSION ?= v2.2.2 -GOFUMPT_VERSION ?= v0.8.0 -GO_VERSION ?= 1.24.5 +GOIMPORTS_VERSION ?= 0.38.0 +GOMOCK_VERSION ?= 0.6.0 +DEEPCOPY_VERSION ?= v0.5.8 +GOLANGCILINT_VERSION ?= v2.6.1 +GOFUMPT_VERSION ?= v0.9.2 +GO_VERSION ?= 1.25.4 GO_BUILDFLAGS ?= GO_LDFLAGS ?= CGO_ENABLED ?= 0 GOTOOLCHAIN ?= local -GOEXPERIMENT ?= synctest +GOEXPERIMENT ?= TESTPKGS ?= ./... KRES_IMAGE ?= ghcr.io/siderolabs/kres:latest CONFORMANCE_IMAGE ?= ghcr.io/siderolabs/conform:latest @@ -72,7 +72,7 @@ COMMON_ARGS += --build-arg=DEEPCOPY_VERSION="$(DEEPCOPY_VERSION)" COMMON_ARGS += --build-arg=GOLANGCILINT_VERSION="$(GOLANGCILINT_VERSION)" COMMON_ARGS += --build-arg=GOFUMPT_VERSION="$(GOFUMPT_VERSION)" COMMON_ARGS += --build-arg=TESTPKGS="$(TESTPKGS)" -TOOLCHAIN ?= docker.io/golang:1.24-alpine +TOOLCHAIN ?= docker.io/golang:1.25-alpine # help menu @@ -166,6 +166,9 @@ local-%: ## Builds the specified target defined in the Dockerfile using the loc lint-golangci-lint: ## Runs golangci-lint linter. @$(MAKE) target-$@ +lint-golangci-lint-fmt: ## Runs golangci-lint formatter and tries to fix issues automatically. + @$(MAKE) local-$@ DEST=. + lint-gofumpt: ## Runs gofumpt linter. @$(MAKE) target-$@ @@ -201,6 +204,9 @@ lint-markdown: ## Runs markdownlint. .PHONY: lint lint: lint-golangci-lint lint-gofumpt lint-govulncheck lint-markdown ## Run all linters for the project. +.PHONY: lint-fmt +lint-fmt: lint-golangci-lint-fmt ## Run all linter formatters and fix up the source tree. + .PHONY: rekres rekres: @docker pull $(KRES_IMAGE) diff --git a/blkid/blkid_linux_test.go b/blkid/blkid_linux_test.go index f0c24d0..8c750f0 100644 --- a/blkid/blkid_linux_test.go +++ b/blkid/blkid_linux_test.go @@ -47,7 +47,7 @@ const ( func xfsSetup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkfs.xfs", "--unsupported", "-L", "somelabel", path) + cmd := exec.CommandContext(t.Context(), "mkfs.xfs", "--unsupported", "-L", "somelabel", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -57,7 +57,7 @@ func xfsSetup(t *testing.T, path string) { func ext2Setup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkfs.ext2", "-L", "extlabel", path) + cmd := exec.CommandContext(t.Context(), "mkfs.ext2", "-L", "extlabel", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -67,7 +67,7 @@ func ext2Setup(t *testing.T, path string) { func ext3Setup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkfs.ext3", "-L", "extlabel", path) + cmd := exec.CommandContext(t.Context(), "mkfs.ext3", "-L", "extlabel", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -77,7 +77,7 @@ func ext3Setup(t *testing.T, path string) { func ext4Setup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkfs.ext4", "-L", "extlabel", path) + cmd := exec.CommandContext(t.Context(), "mkfs.ext4", "-L", "extlabel", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -88,7 +88,7 @@ func vfatSetup(bits int) func(t *testing.T, path string) { return func(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkfs.vfat", "-F", strconv.Itoa(bits), "-n", "TALOS_V1", "-v", path) + cmd := exec.CommandContext(t.Context(), "mkfs.vfat", "-F", strconv.Itoa(bits), "-n", "TALOS_V1", "-v", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -99,7 +99,7 @@ func vfatSetup(bits int) func(t *testing.T, path string) { func luksSetup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("cryptsetup", "luksFormat", "--label", "cryptlabel", "--key-file", "/dev/urandom", "--keyfile-size", "32", path) + cmd := exec.CommandContext(t.Context(), "cryptsetup", "luksFormat", "--label", "cryptlabel", "--key-file", "/dev/urandom", "--keyfile-size", "32", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -150,7 +150,7 @@ func isoSetup(useJoilet bool) func(t *testing.T, path string) { args = append(args, contents) - cmd := exec.Command("mkisofs", args...) + cmd := exec.CommandContext(t.Context(), "mkisofs", args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -161,7 +161,7 @@ func isoSetup(useJoilet bool) func(t *testing.T, path string) { func swapSetup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkswap", "--label", "swaplabel", "-p", "8192", path) + cmd := exec.CommandContext(t.Context(), "mkswap", "--label", "swaplabel", "-p", "8192", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -171,7 +171,7 @@ func swapSetup(t *testing.T, path string) { func swapSetup2(t *testing.T, path string) { t.Helper() - cmd := exec.Command("mkswap", "--label", "swapswap", "-p", "4096", path) + cmd := exec.CommandContext(t.Context(), "mkswap", "--label", "swapswap", "-p", "4096", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -181,7 +181,7 @@ func swapSetup2(t *testing.T, path string) { func lvm2Setup(t *testing.T, path string) { t.Helper() - cmd := exec.Command("pvcreate", "-v", path) + cmd := exec.CommandContext(t.Context(), "pvcreate", "-v", path) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -209,7 +209,7 @@ func squashfsSetup(t *testing.T, path string) { require.NoError(t, f.Close()) - cmd := exec.Command("mksquashfs", contents, path, "-all-root", "-noappend", "-no-progress", "-no-compression") + cmd := exec.CommandContext(t.Context(), "mksquashfs", contents, path, "-all-root", "-noappend", "-no-progress", "-no-compression") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -627,7 +627,7 @@ size= 204800, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=7F5FCD6C-A703 type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=0F06E81A-E78D-426B-A078-30A01AAB3FB7, name="EPHEMERAL" `) - cmd := exec.Command("sfdisk", path) + cmd := exec.CommandContext(t.Context(), "sfdisk", path) cmd.Stdin = strings.NewReader(script) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -659,7 +659,7 @@ size= 204800, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=3C047FF8-E35C type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=0F06E81A-E78D-426B-A078-30A01AAB3FB7, name="TEST2" `) - cmd := exec.Command("sfdisk", rawImage) + cmd := exec.CommandContext(t.Context(), "sfdisk", rawImage) cmd.Stdin = strings.NewReader(script) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -1040,7 +1040,7 @@ func setupNestedGPT(t *testing.T, path string) { setupGPT(t, path) - require.NoError(t, exec.Command("partprobe", path).Run()) + require.NoError(t, exec.CommandContext(t.Context(), "partprobe", path).Run()) vfatSetup(16)(t, path+"p1") ext4Setup(t, path+"p3") diff --git a/block/device_linux_test.go b/block/device_linux_test.go index e7786be..3d5b99c 100644 --- a/block/device_linux_test.go +++ b/block/device_linux_test.go @@ -61,14 +61,14 @@ func TestDevice(t *testing.T) { type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=0F06E81A-E78D-426B-A078-30A01AAB3FB7, name="EPHEMERAL" `) - cmd := exec.Command("sfdisk", devPath) + cmd := exec.CommandContext(t.Context(), "sfdisk", devPath) cmd.Stdin = strings.NewReader(script) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr require.NoError(t, cmd.Run()) - cmd = exec.Command("partprobe", devPath) + cmd = exec.CommandContext(t.Context(), "partprobe", devPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/encryption/luks/luks.go b/encryption/luks/luks.go index 82674f1..519c715 100644 --- a/encryption/luks/luks.go +++ b/encryption/luks/luks.go @@ -73,6 +73,9 @@ const ( XChaCha12String = "xchacha12,aes-adiantum-plain64" // XChaCha20String string representation of xchacha20 cipher. XChaCha20String = "xchacha20,aes-adiantum-plain64" +) + +const ( // AESXTSPlain64Cipher represents aes-xts-plain64 encryption cipher. AESXTSPlain64Cipher Cipher = iota // XChaCha12Cipher represents xchacha12 encryption cipher. diff --git a/encryption/luks/luks_test.go b/encryption/luks/luks_test.go index 530da5e..5900b35 100644 --- a/encryption/luks/luks_test.go +++ b/encryption/luks/luks_test.go @@ -134,7 +134,7 @@ func testEncrypt(t *testing.T) { mountPath := t.TempDir() - cmd := exec.Command("mkfs.vfat", "-F", "32", "-n", "config", encryptedPath) + cmd := exec.CommandContext(t.Context(), "mkfs.vfat", "-F", "32", "-n", "config", encryptedPath) require.NoError(t, cmd.Run()) type SealedKey struct { diff --git a/encryption/luks/options.go b/encryption/luks/options.go index 01b16d4..544b3f4 100644 --- a/encryption/luks/options.go +++ b/encryption/luks/options.go @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Package luks provides a way to call LUKS2 cryptsetup. package luks import "time" diff --git a/hack/govulncheck.sh b/hack/govulncheck.sh new file mode 100644 index 0000000..121c50b --- /dev/null +++ b/hack/govulncheck.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# Source: https://github.com/tianon/gosu/blob/e157efb/govulncheck-with-excludes.sh +# Licensed under the Apache License, Version 2.0 +# Copyright Tianon Gravi +set -Eeuo pipefail + +exclude_arg="" +pass_args=() + +while [[ $# -gt 0 ]]; do + case "$1" in + -exclude) + exclude_arg="$2" + shift 2 + ;; + *) + pass_args+=("$1") + shift + ;; + esac +done + +if [[ -n "$exclude_arg" ]]; then + excludeVulns="$(jq -nc --arg list "$exclude_arg" '$list | split(",")')" +else + excludeVulns="[]" +fi + +export excludeVulns + +# Debug print +echo "excludeVulns = $excludeVulns" +echo "Passing args: ${pass_args[*]}" + +if ! command -v govulncheck > /dev/null; then + printf "govulncheck not installed" + exit 1 +fi + +if out="$(govulncheck "${pass_args[@]}")"; then + printf '%s\n' "$out" + exit 0 +fi + +json="$(govulncheck -json "${pass_args[@]}")" + +vulns="$(jq <<<"$json" -cs ' + ( + map( + .osv // empty + | { key: .id, value: . } + ) + | from_entries + ) as $meta + # https://github.com/tianon/gosu/issues/144 + | map( + .finding // empty + # https://github.com/golang/vuln/blob/3740f5cb12a3f93b18dbe200c4bcb6256f8586e2/internal/scan/template.go#L97-L104 + | select((.trace[0].function // "") != "") + | .osv + ) + | unique + | map($meta[.]) +')" +if [ "$(jq <<<"$vulns" -r 'length')" -le 0 ]; then + printf '%s\n' "$out" + exit 1 +fi + +filtered="$(jq <<<"$vulns" -c ' + (env.excludeVulns | fromjson) as $exclude + | map(select( + .id as $id + | $exclude | index($id) | not + )) +')" + +text="$(jq <<<"$filtered" -r 'map("- \(.id) (aka \(.aliases | join(", ")))\n\n\t\(.details | gsub("\n"; "\n\t"))") | join("\n\n")')" + +if [ -z "$text" ]; then + printf 'No vulnerabilities found.\n' + exit 0 +else + printf '%s\n' "$text" + exit 1 +fi diff --git a/partitioning/gpt/gpt_test.go b/partitioning/gpt/gpt_test.go index 75f86fa..d5b84ed 100644 --- a/partitioning/gpt/gpt_test.go +++ b/partitioning/gpt/gpt_test.go @@ -36,7 +36,7 @@ const ( func sfdiskDump(t *testing.T, devPath string) string { t.Helper() - cmd := exec.Command("sfdisk", "--dump", devPath) + cmd := exec.CommandContext(t.Context(), "sfdisk", "--dump", devPath) cmd.Stderr = os.Stderr out, err := cmd.Output() assert.NoError(t, err) @@ -53,7 +53,7 @@ func sfdiskDump(t *testing.T, devPath string) string { func gdiskDump(t *testing.T, devPath string) string { t.Helper() - cmd := exec.Command("gdisk", "-l", devPath) + cmd := exec.CommandContext(t.Context(), "gdisk", "-l", devPath) cmd.Stderr = os.Stderr out, err := cmd.Output() assert.NoError(t, err) @@ -89,6 +89,7 @@ func assertAllocated(t *testing.T, expectedIndex int) func(_ int, _ gpt.Partitio } } +//nolint:maintidx func TestGPT(t *testing.T) { if os.Geteuid() != 0 { t.Skip("test requires root privileges")