mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(scanner): clamp oversized MergerFS inodes before storage (#30)
* fix(scanner): clamp oversized MergerFS inodes before storage
MergerFS generates synthetic unsigned 64-bit inodes by hashing file paths.
Values above 2^63-1 overflow PostgreSQL's signed bigint column, crashing
the scanner with 'value out of range for type bigint'.
Switch all file stat() calls to stat(path, { bigint: true }) to read
inodes as precise BigInt values instead of lossy JS numbers. Introduce
clampIno(ino: bigint): number which returns 0 for any inode exceeding
PostgreSQL's bigint max - 0 is the existing sentinel meaning 'rename
detection disabled', so no other code needs to change.
The fix covers all four code paths that write ino to a FileStat:
statFilesIntoAcc and buildSingleBookCandidate in walk.ts, plus the two
targeted-scan paths in scanner.service.ts.
Fixes #19
* ci: add maintainer-gated PR GHCR image publish
---------
Signed-off-by: neon <18559658+neonsolstice@users.noreply.github.com>
This commit is contained in:
+109
-3
@@ -23,6 +23,8 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24"
|
||||
PNPM_VERSION: "10"
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
@@ -246,7 +248,7 @@ jobs:
|
||||
(needs.dependency-review.result == 'success' || needs.dependency-review.result == 'skipped') &&
|
||||
needs.detect-changes.result == 'success'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
matrix:
|
||||
package: [server, client]
|
||||
include:
|
||||
@@ -318,7 +320,7 @@ jobs:
|
||||
(needs.dependency-review.result == 'success' || needs.dependency-review.result == 'skipped') &&
|
||||
needs.detect-changes.result == 'success'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
matrix:
|
||||
package: [server, client]
|
||||
include:
|
||||
@@ -379,7 +381,7 @@ jobs:
|
||||
(needs.dependency-review.result == 'success' || needs.dependency-review.result == 'skipped') &&
|
||||
needs.detect-changes.result == 'success'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: ${{ github.event_name == 'pull_request' }}
|
||||
matrix:
|
||||
package: [server, client]
|
||||
include:
|
||||
@@ -556,6 +558,110 @@ jobs:
|
||||
echo "e2e-setup=${{ needs.e2e-setup.result }}"
|
||||
echo "e2e=${{ needs.e2e.result }}"
|
||||
|
||||
pr-image-scan:
|
||||
name: PR Image Scan
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ci-gate]
|
||||
timeout-minutes: 45
|
||||
if: >
|
||||
always() &&
|
||||
github.event_name == 'pull_request' &&
|
||||
needs.ci-gate.result == 'success'
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Prepare PR image tag
|
||||
id: pr-meta
|
||||
shell: bash
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
short_sha="${HEAD_SHA:0:12}"
|
||||
scan_tag="pr-scan-${PR_NUMBER}-${short_sha}"
|
||||
echo "scan_tag=${scan_tag}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Build image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: false
|
||||
load: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.pr-meta.outputs.scan_tag }}
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha,scope=ci-yml-pr-image
|
||||
cache-to: type=gha,mode=max,scope=ci-yml-pr-image
|
||||
|
||||
- name: Scan image with Trivy
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.pr-meta.outputs.scan_tag }}
|
||||
format: table
|
||||
vuln-type: os,library
|
||||
severity: CRITICAL,HIGH
|
||||
ignore-unfixed: true
|
||||
exit-code: "1"
|
||||
|
||||
pr-image-publish:
|
||||
name: PR Image Publish
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ci-gate, pr-image-scan]
|
||||
timeout-minutes: 45
|
||||
if: >
|
||||
always() &&
|
||||
github.event_name == 'pull_request' &&
|
||||
needs.ci-gate.result == 'success' &&
|
||||
needs.pr-image-scan.result == 'success' &&
|
||||
github.event.pull_request.head.repo.full_name == github.repository &&
|
||||
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Prepare PR publish tag
|
||||
id: pr-meta
|
||||
shell: bash
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
short_sha="${HEAD_SHA:0:12}"
|
||||
publish_tag="pr-${PR_NUMBER}-${short_sha}"
|
||||
echo "publish_tag=${publish_tag}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GHCR_TOKEN != '' && secrets.GHCR_TOKEN || github.token }}
|
||||
|
||||
- name: Build and push PR image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.pr-meta.outputs.publish_tag }}
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha,scope=ci-yml-pr-image
|
||||
cache-to: type=gha,mode=max,scope=ci-yml-pr-image
|
||||
|
||||
ci-performance:
|
||||
name: CI Performance
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
name: Container Image
|
||||
run-name: >-
|
||||
${{ github.event_name == 'workflow_run' && format('Image - {0} ({1})', github.event.workflow_run.head_commit.message, github.event.workflow_run.head_branch) || github.event_name == 'pull_request' && format('Image check - PR #{0}', github.event.pull_request.number) || format('Image - {0}', github.ref_name) }}
|
||||
${{ github.event_name == 'workflow_run' && format('Image - {0} ({1})', github.event.workflow_run.head_commit.message, github.event.workflow_run.head_branch) || format('Image - {0}', github.ref_name) }}
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
# Break-glass: bypasses CI/E2E gate. Use only when CI is broken and a hotfix image is urgently needed.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -18,7 +16,7 @@ on:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.sha }}
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
@@ -30,43 +28,6 @@ env:
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
# PR path: amd64-only build and scan for fast feedback. No push.
|
||||
scan:
|
||||
name: Build and Scan Image
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Build image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: false
|
||||
load: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-scan
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha,scope=container-image-yml-pr
|
||||
cache-to: type=gha,mode=max,scope=container-image-yml-pr
|
||||
|
||||
- name: Scan image with Trivy
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-scan
|
||||
format: table
|
||||
vuln-type: os,library
|
||||
severity: CRITICAL,HIGH
|
||||
ignore-unfixed: true
|
||||
exit-code: "1"
|
||||
|
||||
# Main push path: resolve context once, then build multi-arch natively in parallel.
|
||||
prepare:
|
||||
name: Resolve Build Context
|
||||
|
||||
Reference in New Issue
Block a user