Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
4294ddc
test(supply-chain): require deterministic npm lock generator
seonghobae Aug 7, 2026
afb20be
fix(supply-chain): pin npm lock generator metadata
seonghobae Aug 7, 2026
e64c229
ci(supply-chain): prove npm version and lock reproduction
seonghobae Aug 7, 2026
ebbde9b
docs(supply-chain): record npm generator provenance
seonghobae Aug 7, 2026
694ca83
docs(changelog): record npm generator contract
seonghobae Aug 7, 2026
90dc2a0
fix(supply-chain): avoid serializing npm into runtime engines
seonghobae Aug 7, 2026
fecc36b
test(supply-chain): keep npm enforcement out of runtime engines
seonghobae Aug 7, 2026
9eb83c3
docs(supply-chain): separate npm generator from runtime engines
seonghobae Aug 7, 2026
5609b88
ci(supply-chain): publish deterministic lock reproduction evidence
seonghobae Aug 7, 2026
032314d
test(supply-chain): require preserved lock reproduction evidence
seonghobae Aug 7, 2026
0263ad4
test(security): require coordinated PDF.js and Undici baseline
seonghobae Aug 7, 2026
2cbf767
test(security): disable PDF expression evaluation
seonghobae Aug 7, 2026
475de96
fix(security): pin the patched Undici transitive version
seonghobae Aug 7, 2026
deb74ac
fix(security): pin the patched PDF.js release
seonghobae Aug 7, 2026
dc90d5b
fix(security): disable PDF expression evaluation
seonghobae Aug 7, 2026
b23b957
docs(security): record coordinated PDF and HTTP remediation
seonghobae Aug 7, 2026
2e99f72
docs(changelog): record coordinated security remediation
seonghobae Aug 7, 2026
8f50fe4
fix(security): anchor the Undici override to an exact root floor
seonghobae Aug 7, 2026
e2c0c2d
test(security): bind exact root floor and npm package locations
seonghobae Aug 7, 2026
dd93f96
ci(pr783): import exact npm 10.9.8 lock artifact
seonghobae Aug 7, 2026
dd8d1ac
fix(score): align PDF.js boundary with 6.2.108 API
seonghobae Aug 7, 2026
988dc1d
test(score): prove the supported data-only PDF.js boundary
seonghobae Aug 7, 2026
a39e37f
docs(security): record the supported PDF.js 6.2.108 boundary
seonghobae Aug 7, 2026
6b753e6
docs(changelog): describe the supported patched PDF boundary
seonghobae Aug 7, 2026
b773653
ci(pr783): rerun lock import after supported API repair
seonghobae Aug 7, 2026
01cb39e
ci(pr783): publish the verified lock from the bounded importer
seonghobae Aug 7, 2026
ad558ac
ci(pr783): fetch complete lineage for verified lock publication
seonghobae Aug 7, 2026
83865dc
fix(security): import verified npm 10.9.8 lock
github-actions[bot] Aug 7, 2026
e6b48ca
test(ci): preserve canonical npm provenance formatting
seonghobae Aug 7, 2026
3edf173
ci(pr783): diagnose Ruff import ordering
seonghobae Aug 7, 2026
2345219
style(ci): normalize security test imports
seonghobae Aug 7, 2026
dc7e8b4
style(ci): normalize npm provenance test imports
seonghobae Aug 7, 2026
c5ee630
chore(ci): remove completed Ruff diagnostic
seonghobae Aug 7, 2026
f0c9ad1
ci(pr783): finalize exact Ruff formatting
seonghobae Aug 7, 2026
102a89f
chore(ci): remove temporary branch writer
seonghobae Aug 7, 2026
d4887ec
style(test): apply Ruff formatting to security contracts
seonghobae Aug 7, 2026
459abdd
style(test): finish Ruff formatting for npm provenance
seonghobae Aug 7, 2026
ace4257
fix(security): refresh vulnerable npm transitive pins
seonghobae Aug 11, 2026
63d0ae6
fix(deps): restore manifest-lock consistency
seonghobae Aug 11, 2026
6bba612
ci: add one-shot canonical lock repair for PR 783
seonghobae Aug 14, 2026
ef938fa
fix(deps): regenerate canonical npm 10.9.8 lock
github-actions[bot] Aug 14, 2026
a48ff96
ci: retrigger exact-head validation after canonical lock generation
seonghobae Aug 14, 2026
fd9389a
ci: add one-shot Ruff formatter for PR 783
seonghobae Aug 14, 2026
afba132
style(test): apply canonical Ruff formatting
github-actions[bot] Aug 14, 2026
e214e96
ci: retrigger exact-head validation after canonical Ruff formatting
seonghobae Aug 14, 2026
0cd6836
fix(test): verify canonical hoisted PDF.js lock record
seonghobae Aug 14, 2026
f4a5a19
ci: add final one-shot Ruff formatter for PR 783
seonghobae Aug 14, 2026
219267e
style(test): apply final canonical Ruff formatting
github-actions[bot] Aug 14, 2026
db7b1c1
chore(ci): retrigger exact-head protected checks
seonghobae Aug 14, 2026
f4d8850
fix(ci): validate npm lock without mutable resolution
seonghobae Aug 14, 2026
8a143ab
test(supply-chain): format npm toolchain contract
seonghobae Aug 14, 2026
b3ac826
test(supply-chain): satisfy ruff formatting gate
seonghobae Aug 14, 2026
885c037
test(supply-chain): format npm toolchain contract
seonghobae Aug 14, 2026
de0cd6b
test(supply-chain): apply repository Ruff width
seonghobae Aug 14, 2026
f3cfae4
docs(security): align npm lock provenance with frozen validation
seonghobae Aug 14, 2026
de75178
fix(ci): disable persisted checkout credentials
seonghobae Aug 14, 2026
164e6f2
docs(changelog): correct UI test coverage claim
seonghobae Aug 14, 2026
07c1dd2
test(lock): reject esbuild peer metadata drift
seonghobae Aug 15, 2026
ad4551b
docs(lock): record esbuild metadata sentinel
seonghobae Aug 15, 2026
6f81f52
docs(changelog): record lock metadata drift gate
seonghobae Aug 15, 2026
6665f02
fix(security): make PDF XML boundary explicit
seonghobae Aug 15, 2026
bf5a3a3
test(security): lock down PDF parser options
seonghobae Aug 15, 2026
c65f5b1
docs(security): record PDF parser hardening evidence
seonghobae Aug 15, 2026
dae5d3c
docs(security): correct PDF.js advisory attribution
seonghobae Aug 15, 2026
d1d8641
test: measure Python branch coverage
seonghobae Aug 16, 2026
2b543d5
test: cover previously hidden Python branch arcs
seonghobae Aug 16, 2026
4ec36a6
refactor: remove impossible handoff membership branch
seonghobae Aug 16, 2026
e18894a
style: format branch-coverage source repair
seonghobae Aug 16, 2026
42e0b16
chore: run one-shot Ruff formatter for PR 861
seonghobae Aug 16, 2026
f3a0c27
style: apply repository Python formatter
github-actions[bot] Aug 16, 2026
fcf7e52
test: revalidate formatted branch-coverage head
seonghobae Aug 16, 2026
6afbc9f
test: cover flat novelty normalization branch
seonghobae Aug 16, 2026
ce35d3d
test(ci): require credential-free lock validation checkout
seonghobae Aug 18, 2026
99e6be9
fix(ci): drop checkout credentials from lock validation
seonghobae Aug 18, 2026
0130f7b
merge(quality): compose dependency security with branch coverage
seonghobae Aug 20, 2026
f8dc2e1
test(score): prove PDF byte-buffer isolation
seonghobae Aug 20, 2026
06e060b
test(coverage): prove shared-hit scan reaches later stems
seonghobae Aug 20, 2026
4fac4e7
test(supply-chain): validate npm CI structure fail-closed
seonghobae Aug 20, 2026
4450416
test(supply-chain): reject vulnerable npm tar runtime
seonghobae Aug 20, 2026
b77ff7c
fix(supply-chain): verify patched npm tar runtime
seonghobae Aug 20, 2026
1cd71db
fix(supply-chain): pin patched npm runtime
seonghobae Aug 20, 2026
f29622d
fix(ci): activate patched npm before dependency reads
seonghobae Aug 20, 2026
9e06df0
docs(supply-chain): record patched npm runtime boundary
seonghobae Aug 20, 2026
ec40dda
docs(security): align dependency baseline with patched npm
seonghobae Aug 20, 2026
c516f1d
docs(changelog): record patched npm tar runtime
seonghobae Aug 20, 2026
81b2901
test(ci): expose pre-Corepack npm cache bootstrap
seonghobae Aug 20, 2026
27a633d
fix(ci): defer npm use until pinned Corepack runtime
seonghobae Aug 20, 2026
05ca286
fix(release): activate pinned npm before dependency install
seonghobae Aug 20, 2026
cf1b728
fix(security): verify pinned npm before audit install
seonghobae Aug 20, 2026
0facdbf
fix(build): use pinned npm after Corepack activation
seonghobae Aug 20, 2026
96674b2
test(ci): accept combined npm activation audit step
seonghobae Aug 20, 2026
db4aa09
fix(ci): disable checkout credentials for npm consumers
seonghobae Aug 24, 2026
1168c8f
chore(ci): re-trigger required checks after provider-prefix migration
seonghobae Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions .github/workflows/build-baseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand Down Expand Up @@ -90,6 +90,10 @@ jobs:
}

Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner."
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
Comment thread
seonghobae marked this conversation as resolved.
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -134,7 +138,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand Down Expand Up @@ -185,6 +189,10 @@ jobs:
}

Write-AntivirusEvidence "Antivirus check: no explicit antivirus telemetry was available on this hosted runner."
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -240,7 +248,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -254,6 +262,10 @@ jobs:
run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable
- name: Install create-dmg
run: brew install create-dmg
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down Expand Up @@ -298,7 +310,7 @@ jobs:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -312,6 +324,10 @@ jobs:
run: rustup target add "$BANDSCOPE_TARGET_TRIPLE" --toolchain stable
- name: Install create-dmg
run: brew install create-dmg
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down
49 changes: 45 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,49 @@ env:
GIT_CONFIG_COUNT: "1"
GIT_CONFIG_KEY_0: init.defaultBranch
GIT_CONFIG_VALUE_0: develop
EXPECTED_NPM_VERSION: "10.9.9"

jobs:
lock-validation:
name: gate / ci / npm-lock-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
- name: Validate the frozen package lock without lifecycle execution
run: npm ci --ignore-scripts --no-audit --no-fund
- name: Reject manifest or lockfile drift
run: git diff --exit-code -- package.json package-lock.json

verify:
name: ci / build-and-test
needs: lock-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
Comment thread
seonghobae marked this conversation as resolved.
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.8.6"
Expand All @@ -51,13 +83,22 @@ jobs:

rust-check:
name: gate / ci / rust-check
needs: lock-validation
runs-on: macos-15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
node-version: "22.22.3"
package-manager-cache: false
- name: Activate pinned npm runtime
run: corepack enable npm
- name: Verify exact npm lockfile generator and bundled tar
run: |
test "$(npm --version)" = "$EXPECTED_NPM_VERSION"
npm run check:npm-runtime
- name: Install stable Rust toolchain
run: rustup toolchain install stable --profile minimal
- name: Install node dependencies
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ jobs:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
Expand All @@ -42,6 +44,10 @@ jobs:
enable-cache: false
- name: Install Rust stable
run: rustup toolchain install stable --profile minimal
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Sync Python dependencies
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/security-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22.22.3
cache: npm
package-manager-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
with:
version: "0.8.6"
enable-cache: false
- name: Activate and verify pinned npm runtime
run: |
corepack enable npm
npm run check:npm-runtime
- name: Install node dependencies
run: npm ci
- name: Audit npm dependencies
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
- Display the analyzed song tempo (BPM) as a badge in the rehearsal workspace.
- 각 합주 역할(Role)별 개인 연습 진행도를 0~100% 범위로 기록 및 시각화할 수 있는 연습 진척도(`practiceProgress`) 트래커 기능 추가. UI 컨트롤(슬라이더 및 +/- 버튼)과 한/영 다국어 지원 포함.

### Changed

- Pinned npm `10.9.9` as the approved lockfile generator, activated it through Node-bundled Corepack before dependency consumption, and fail closed unless its bundled `tar` is at least `7.5.19`; primary CI still consumes the committed lock only through frozen `npm ci` validation, rejects mutable npm resolution in the lock gate, requires integrity evidence for public-registry lock entries, and preserves generator-sensitive root `@esbuild/*` peer metadata.

### Fixed

- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and constrained PDF loading to copied in-memory bytes with a same-origin bundled worker and npm-generated lock provenance.

## [0.1.3] - 2026-04-29

### Fixed
Expand Down Expand Up @@ -65,4 +73,4 @@

- `ChordsFeature` (코드 분석) 화면에서 각 파트(Role)의 `transpositionPlan`(이조/조옮김 계획)을 표시하는 기능을 추가했습니다.
- `RangesFeature` (음역대 분석) 화면에서 겹침 경고(Overlap warning) 외에 해당 파트의 채보(Transcription) 가능 노드 수를 요약하여 보여주는 기능을 추가했습니다.
- 신규 UI 요소에 대한 100% 테스트 커버리지를 보장하는 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
- 신규 UI 요소에 대한 단위 테스트를 추가했습니다 (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.24.0",
"pdfjs-dist": "6.1.200",
"pdfjs-dist": "6.2.108",
"react": "^19.2.4",
"react-dom": "^19.2.7",
"sonner": "^2.0.7",
Expand Down
54 changes: 54 additions & 0 deletions apps/desktop/src/features/score/pdfjs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
import { configureScorePdfWorker, loadScorePdf } from "./pdfjs";

vi.mock("pdfjs-dist", () => ({
getDocument: vi.fn(() => ({ promise: Promise.resolve(), destroy: vi.fn() })),
GlobalWorkerOptions: { workerSrc: "" }
}));

vi.mock("pdfjs-dist/build/pdf.worker.min.mjs?url", () => ({
default: "/assets/pdf.worker.min.mjs"
}));

describe("score PDF.js boundary", () => {
beforeEach(() => {
vi.mocked(getDocument).mockClear();
GlobalWorkerOptions.workerSrc = "";
});

it("uses the locally bundled worker asset", () => {
configureScorePdfWorker();

expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs");

configureScorePdfWorker();
expect(GlobalWorkerOptions.workerSrc).toBe("/assets/pdf.worker.min.mjs");
});

it("copies validated bytes through the hardened data-only API", () => {
const source = new Uint8Array([0x25, 0x50, 0x44, 0x46]);

loadScorePdf(source);

expect(getDocument).toHaveBeenCalledTimes(1);
const parameters = vi.mocked(getDocument).mock.calls[0]?.[0];
expect(parameters).toBeTypeOf("object");
expect(Object.keys(parameters as object)).toEqual([
"data",
"enableXfa",
"useWorkerFetch"
]);
const hardenedParameters = parameters as {
data: Uint8Array;
enableXfa: boolean;
useWorkerFetch: boolean;
};
expect(hardenedParameters.data).toEqual(source);
expect(hardenedParameters.data).not.toBe(source);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
source[0] = 0x00;
expect(hardenedParameters.data[0]).toBe(0x25);
expect(hardenedParameters.enableXfa).toBe(false);
expect(hardenedParameters.useWorkerFetch).toBe(false);
});
});
18 changes: 15 additions & 3 deletions apps/desktop/src/features/score/pdfjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,23 @@ export function configureScorePdfWorker(): void {
* Start parsing validated in-memory score PDF bytes with pdf.js.
*
* Only caller-provided bytes are accepted (validated-resource-only rule);
* this helper never fetches arbitrary URLs. The bytes are copied before they
* are handed to pdf.js because pdf.js transfers the underlying buffer to its
* this helper never supplies a URL. The bytes are copied before they are
* handed to pdf.js because pdf.js transfers the underlying buffer to its
* worker, which would otherwise detach the caller's copy and break retries.
*
* XFA rendering is explicitly disabled even though pdf.js 6.2.108 defaults it
* to `false`, and worker-side resource fetching is explicitly disabled. These
* settings make the parser boundary fail closed against XML-form activation
* and remote helper-resource acquisition instead of relying on upstream
* defaults. In the pinned pdf.js XML parser, DOCTYPE declarations are reported
* to a no-op hook and unknown named entities are preserved literally rather
* than dereferenced, so no external-entity resolver is exposed by this API.
*/
export function loadScorePdf(data: Uint8Array): PDFDocumentLoadingTask {
configureScorePdfWorker();
return getDocument({ data: new Uint8Array(data) });
return getDocument({
data: new Uint8Array(data),
enableXfa: false,
useWorkerFetch: false
});
}
Loading
Loading