ci: address code scanning scorecard alerts (#4275)
This commit is contained in:
@@ -15,10 +15,12 @@ concurrency:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -42,10 +44,10 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -53,13 +55,13 @@ jobs:
|
||||
|
||||
- name: Docker meta (for labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/readest
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
@@ -87,6 +89,9 @@ jobs:
|
||||
|
||||
merge:
|
||||
needs: build
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download digests
|
||||
@@ -97,10 +102,10 @@ jobs:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -117,7 +122,7 @@ jobs:
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: steps.dockerhub.outputs.enabled == 'true'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -125,7 +130,7 @@ jobs:
|
||||
- name: Extract image metadata (GHCR only)
|
||||
id: meta-ghcr
|
||||
if: steps.dockerhub.outputs.enabled != 'true'
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/readest
|
||||
tags: |
|
||||
@@ -137,7 +142,7 @@ jobs:
|
||||
- name: Extract image metadata (GHCR + Docker Hub)
|
||||
id: meta-all
|
||||
if: steps.dockerhub.outputs.enabled == 'true'
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/${{ github.repository_owner }}/readest
|
||||
|
||||
@@ -10,7 +10,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
@@ -18,7 +17,7 @@ jobs:
|
||||
- uses: amondnet/vercel-action@de09aeac2ace6599ec9b11ef87558759a496bac4 # v42
|
||||
with:
|
||||
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github-comment: false
|
||||
vercel-args: '--prod'
|
||||
vercel-org-id: ${{ secrets.ORG_ID}}
|
||||
vercel-project-id: ${{ secrets.PROJECT_ID}}
|
||||
|
||||
@@ -235,6 +235,7 @@
|
||||
"cpx2": "^8.0.0",
|
||||
"daisyui": "^4.12.24",
|
||||
"dotenv-cli": "^7.4.4",
|
||||
"fast-check": "^4.8.0",
|
||||
"i18next-scanner": "^4.6.0",
|
||||
"jsdom": "^28.1.0",
|
||||
"mkdirp": "^3.0.1",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import fc from 'fast-check';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { makeSafeFilename } from '../../utils/misc';
|
||||
|
||||
@@ -53,6 +54,11 @@ describe('makeSafeFilename', () => {
|
||||
expect(makeSafeFilename('LPT9')).toBe('LPT9_');
|
||||
});
|
||||
|
||||
it('should handle reserved names after trimming whitespace', () => {
|
||||
expect(makeSafeFilename(' CON ')).toBe('CON_');
|
||||
expect(makeSafeFilename(' prn ')).toBe('prn_');
|
||||
});
|
||||
|
||||
it('should not affect reserved names with extensions', () => {
|
||||
// Reserved names only apply to the base name without extension
|
||||
const result = makeSafeFilename('CON.txt');
|
||||
@@ -375,4 +381,20 @@ describe('makeSafeFilename', () => {
|
||||
expect(result).toBe('https___example.com_book.pdf');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Property checks', () => {
|
||||
it('should keep sanitized filenames bounded, safe, trimmed, and stable', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string({ maxLength: 1000 }), (filename) => {
|
||||
const result = makeSafeFilename(filename);
|
||||
|
||||
expect(new TextEncoder().encode(result).length).toBeLessThanOrEqual(250);
|
||||
expect(result).not.toMatch(/[<>:%#"\/\\|?*\x00-\x1F]/);
|
||||
expect(result).toBe(result.trim());
|
||||
expect(makeSafeFilename(result)).toBe(result);
|
||||
}),
|
||||
{ numRuns: 200 },
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ export const makeSafeFilename = (filename: string, replacement = '_') => {
|
||||
// Unsafe to use filename including file extensions over 255 bytes on Android
|
||||
const maxFilenameBytes = 250;
|
||||
|
||||
let safeName = filename.replace(unsafeCharacters, replacement);
|
||||
let safeName = filename.replace(unsafeCharacters, replacement).trim();
|
||||
|
||||
if (reservedFilenames.test(safeName)) {
|
||||
safeName = `${safeName}${replacement}`;
|
||||
@@ -29,7 +29,7 @@ export const makeSafeFilename = (filename: string, replacement = '_') => {
|
||||
utf8Bytes = encoder.encode(safeName);
|
||||
}
|
||||
|
||||
return safeName.trim();
|
||||
return safeName;
|
||||
};
|
||||
|
||||
export const getLocale = () => {
|
||||
|
||||
Generated
+16
@@ -508,6 +508,9 @@ importers:
|
||||
dotenv-cli:
|
||||
specifier: ^7.4.4
|
||||
version: 7.4.4
|
||||
fast-check:
|
||||
specifier: ^4.8.0
|
||||
version: 4.8.0
|
||||
i18next-scanner:
|
||||
specifier: ^4.6.0
|
||||
version: 4.6.0(typescript@5.9.3)
|
||||
@@ -5542,6 +5545,10 @@ packages:
|
||||
engines: {node: '>= 10.17.0'}
|
||||
hasBin: true
|
||||
|
||||
fast-check@4.8.0:
|
||||
resolution: {integrity: sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==}
|
||||
engines: {node: '>=12.17.0'}
|
||||
|
||||
fast-deep-equal@2.0.1:
|
||||
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
|
||||
|
||||
@@ -7300,6 +7307,9 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
pure-rand@8.4.0:
|
||||
resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==}
|
||||
|
||||
qs@6.15.1:
|
||||
resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==}
|
||||
engines: {node: '>=0.6'}
|
||||
@@ -14300,6 +14310,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
fast-check@4.8.0:
|
||||
dependencies:
|
||||
pure-rand: 8.4.0
|
||||
|
||||
fast-deep-equal@2.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
@@ -16422,6 +16436,8 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
pure-rand@8.4.0: {}
|
||||
|
||||
qs@6.15.1:
|
||||
dependencies:
|
||||
side-channel: 1.1.0
|
||||
|
||||
Reference in New Issue
Block a user