From 5a20b101830dc948624e77f668693a1ab4f17caf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 07:08:07 +0900 Subject: [PATCH 1/5] test(security): require nanoid 3.3.18 remediation --- test/package-manager-predecessor-integration.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/package-manager-predecessor-integration.test.ts b/test/package-manager-predecessor-integration.test.ts index 0be6b2290..564876288 100644 --- a/test/package-manager-predecessor-integration.test.ts +++ b/test/package-manager-predecessor-integration.test.ts @@ -16,7 +16,7 @@ const packageLock = JSON.parse(readFileSync("package-lock.json", "utf8")) as { describe("deterministic package-manager work integrated after the nanoid predecessor", () => { it("preserves the predecessor security remediation while pinning the reviewed toolchain", () => { - expect(packageLock.packages?.["node_modules/nanoid"]?.version).toBe("3.3.17"); + expect(packageLock.packages?.["node_modules/nanoid"]?.version).toBe("3.3.18"); expect(packageJson.packageManager).toBe("npm@11.17.0"); expect(packageJson.devEngines?.runtime).toEqual({ name: "node", From d167c1b5394ea1d1d84a8530bd3af055f010401a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:09:32 +0900 Subject: [PATCH 2/5] chore(ci): run one-shot nanoid lockfile remediation --- .github/workflows/repair-nanoid-lockfile.yml | 150 +++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 .github/workflows/repair-nanoid-lockfile.yml diff --git a/.github/workflows/repair-nanoid-lockfile.yml b/.github/workflows/repair-nanoid-lockfile.yml new file mode 100644 index 000000000..2b655cd63 --- /dev/null +++ b/.github/workflows/repair-nanoid-lockfile.yml @@ -0,0 +1,150 @@ +name: repair-nanoid-lockfile +run-name: One-shot nanoid 3.3.18 lockfile remediation + +on: + push: + branches: + - fix/nanoid-cve-2026-67213-3-3-18 + +concurrency: + group: repair-nanoid-lockfile + cancel-in-progress: false + +permissions: + contents: write + +jobs: + repair: + if: >- + github.repository == 'ContextualWisdomLab/noema' && + github.ref == 'refs/heads/fix/nanoid-cve-2026-67213-3-3-18' && + github.actor != 'github-actions[bot]' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + steps: + - name: checkout exact repair branch + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: fix/nanoid-cve-2026-67213-3-3-18 + fetch-depth: 2 + persist-credentials: true + + - name: setup reviewed Node toolchain + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e + with: + node-version: '24.19.0' + cache: npm + + - name: verify reviewed package-manager identity + shell: bash + run: | + set -euo pipefail + test "$(node --version)" = "v24.19.0" + test "$(npm --version)" = "11.17.0" + + - name: regenerate only the vulnerable transitive lock node + shell: bash + run: | + set -euo pipefail + npm update nanoid \ + --package-lock-only \ + --ignore-scripts \ + --legacy-peer-deps=false \ + --install-links=false + + - name: prove the lockfile delta is limited to nanoid 3.3.18 + shell: bash + run: | + set -euo pipefail + node --input-type=module <<'NODE' + import { execFileSync } from "node:child_process"; + import { readFileSync } from "node:fs"; + + const previous = JSON.parse(execFileSync("git", ["show", "HEAD^:package-lock.json"], { encoding: "utf8" })); + const current = JSON.parse(readFileSync("package-lock.json", "utf8")); + const packagePath = "node_modules/nanoid"; + const previousNode = previous.packages?.[packagePath]; + const currentNode = current.packages?.[packagePath]; + + if (previousNode?.version !== "3.3.17") { + throw new Error(`unexpected predecessor nanoid version: ${previousNode?.version ?? "missing"}`); + } + if (currentNode?.version !== "3.3.18") { + throw new Error(`nanoid was not remediated to 3.3.18: ${currentNode?.version ?? "missing"}`); + } + if (currentNode.resolved !== "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz") { + throw new Error("nanoid resolved URL is not the registry-authenticated 3.3.18 artifact"); + } + if (typeof currentNode.integrity !== "string" || !currentNode.integrity.startsWith("sha512-")) { + throw new Error("nanoid 3.3.18 is missing registry integrity metadata"); + } + + const normalize = (lock) => { + const clone = structuredClone(lock); + const node = clone.packages?.[packagePath]; + if (!node) throw new Error("nanoid lock node is missing"); + delete node.version; + delete node.resolved; + delete node.integrity; + return clone; + }; + + if (JSON.stringify(normalize(previous)) !== JSON.stringify(normalize(current))) { + throw new Error("npm changed package metadata outside the reviewed nanoid identity fields"); + } + NODE + + - name: correct the security changelog and remove this one-shot workflow + shell: bash + run: | + set -euo pipefail + node --input-type=module <<'NODE' + import { readFileSync, writeFileSync } from "node:fs"; + + const path = "CHANGELOG.md"; + const original = readFileSync(path, "utf8"); + let updated = original.replace( + "transitive `nanoid` lockfile resolution을 `3.3.16`에서 `3.3.17`로 최소 갱신", + "transitive `nanoid` lockfile resolution을 `3.3.17`에서 `3.3.18`로 최소 갱신", + ); + updated = updated.replace( + "#76의 `nanoid@3.3.17` 보안 수정", + "선행 `nanoid@3.3.18` 보안 수정", + ); + if (updated === original) { + throw new Error("expected nanoid changelog statements were not found"); + } + if (updated.includes("#76의 `nanoid@3.3.17` 보안 수정")) { + throw new Error("stale nanoid 3.3.17 remediation statement remains"); + } + writeFileSync(path, updated, "utf8"); + NODE + rm -- .github/workflows/repair-nanoid-lockfile.yml + + - name: verify frozen install and full release contract + shell: bash + run: | + set -euo pipefail + npm ci --legacy-peer-deps=false --install-links=false + npm run release:verify + + - name: commit the verified minimal GREEN + shell: bash + run: | + set -euo pipefail + git diff --exit-code -- package.json + mapfile -t changed_paths < <(git status --porcelain=v1 | sed -E 's/^.. //') + printf '%s\n' "${changed_paths[@]}" | sort >"$RUNNER_TEMP/changed-paths.txt" + printf '%s\n' \ + .github/workflows/repair-nanoid-lockfile.yml \ + CHANGELOG.md \ + package-lock.json | sort >"$RUNNER_TEMP/expected-paths.txt" + diff -u "$RUNNER_TEMP/expected-paths.txt" "$RUNNER_TEMP/changed-paths.txt" + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -- package-lock.json CHANGELOG.md .github/workflows/repair-nanoid-lockfile.yml + git commit -m "fix(deps): remediate nanoid 3.3.18" + git push origin "HEAD:${GITHUB_REF_NAME}" From c729bfc0c966240cf8b9cd18d5f81dff3f9ad54f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 08:10:09 +0000 Subject: [PATCH 3/5] fix(deps): remediate nanoid 3.3.18 --- .github/workflows/repair-nanoid-lockfile.yml | 150 ------------------- CHANGELOG.md | 4 +- package-lock.json | 6 +- 3 files changed, 5 insertions(+), 155 deletions(-) delete mode 100644 .github/workflows/repair-nanoid-lockfile.yml diff --git a/.github/workflows/repair-nanoid-lockfile.yml b/.github/workflows/repair-nanoid-lockfile.yml deleted file mode 100644 index 2b655cd63..000000000 --- a/.github/workflows/repair-nanoid-lockfile.yml +++ /dev/null @@ -1,150 +0,0 @@ -name: repair-nanoid-lockfile -run-name: One-shot nanoid 3.3.18 lockfile remediation - -on: - push: - branches: - - fix/nanoid-cve-2026-67213-3-3-18 - -concurrency: - group: repair-nanoid-lockfile - cancel-in-progress: false - -permissions: - contents: write - -jobs: - repair: - if: >- - github.repository == 'ContextualWisdomLab/noema' && - github.ref == 'refs/heads/fix/nanoid-cve-2026-67213-3-3-18' && - github.actor != 'github-actions[bot]' - runs-on: ubuntu-24.04 - timeout-minutes: 20 - env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - steps: - - name: checkout exact repair branch - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - ref: fix/nanoid-cve-2026-67213-3-3-18 - fetch-depth: 2 - persist-credentials: true - - - name: setup reviewed Node toolchain - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e - with: - node-version: '24.19.0' - cache: npm - - - name: verify reviewed package-manager identity - shell: bash - run: | - set -euo pipefail - test "$(node --version)" = "v24.19.0" - test "$(npm --version)" = "11.17.0" - - - name: regenerate only the vulnerable transitive lock node - shell: bash - run: | - set -euo pipefail - npm update nanoid \ - --package-lock-only \ - --ignore-scripts \ - --legacy-peer-deps=false \ - --install-links=false - - - name: prove the lockfile delta is limited to nanoid 3.3.18 - shell: bash - run: | - set -euo pipefail - node --input-type=module <<'NODE' - import { execFileSync } from "node:child_process"; - import { readFileSync } from "node:fs"; - - const previous = JSON.parse(execFileSync("git", ["show", "HEAD^:package-lock.json"], { encoding: "utf8" })); - const current = JSON.parse(readFileSync("package-lock.json", "utf8")); - const packagePath = "node_modules/nanoid"; - const previousNode = previous.packages?.[packagePath]; - const currentNode = current.packages?.[packagePath]; - - if (previousNode?.version !== "3.3.17") { - throw new Error(`unexpected predecessor nanoid version: ${previousNode?.version ?? "missing"}`); - } - if (currentNode?.version !== "3.3.18") { - throw new Error(`nanoid was not remediated to 3.3.18: ${currentNode?.version ?? "missing"}`); - } - if (currentNode.resolved !== "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz") { - throw new Error("nanoid resolved URL is not the registry-authenticated 3.3.18 artifact"); - } - if (typeof currentNode.integrity !== "string" || !currentNode.integrity.startsWith("sha512-")) { - throw new Error("nanoid 3.3.18 is missing registry integrity metadata"); - } - - const normalize = (lock) => { - const clone = structuredClone(lock); - const node = clone.packages?.[packagePath]; - if (!node) throw new Error("nanoid lock node is missing"); - delete node.version; - delete node.resolved; - delete node.integrity; - return clone; - }; - - if (JSON.stringify(normalize(previous)) !== JSON.stringify(normalize(current))) { - throw new Error("npm changed package metadata outside the reviewed nanoid identity fields"); - } - NODE - - - name: correct the security changelog and remove this one-shot workflow - shell: bash - run: | - set -euo pipefail - node --input-type=module <<'NODE' - import { readFileSync, writeFileSync } from "node:fs"; - - const path = "CHANGELOG.md"; - const original = readFileSync(path, "utf8"); - let updated = original.replace( - "transitive `nanoid` lockfile resolution을 `3.3.16`에서 `3.3.17`로 최소 갱신", - "transitive `nanoid` lockfile resolution을 `3.3.17`에서 `3.3.18`로 최소 갱신", - ); - updated = updated.replace( - "#76의 `nanoid@3.3.17` 보안 수정", - "선행 `nanoid@3.3.18` 보안 수정", - ); - if (updated === original) { - throw new Error("expected nanoid changelog statements were not found"); - } - if (updated.includes("#76의 `nanoid@3.3.17` 보안 수정")) { - throw new Error("stale nanoid 3.3.17 remediation statement remains"); - } - writeFileSync(path, updated, "utf8"); - NODE - rm -- .github/workflows/repair-nanoid-lockfile.yml - - - name: verify frozen install and full release contract - shell: bash - run: | - set -euo pipefail - npm ci --legacy-peer-deps=false --install-links=false - npm run release:verify - - - name: commit the verified minimal GREEN - shell: bash - run: | - set -euo pipefail - git diff --exit-code -- package.json - mapfile -t changed_paths < <(git status --porcelain=v1 | sed -E 's/^.. //') - printf '%s\n' "${changed_paths[@]}" | sort >"$RUNNER_TEMP/changed-paths.txt" - printf '%s\n' \ - .github/workflows/repair-nanoid-lockfile.yml \ - CHANGELOG.md \ - package-lock.json | sort >"$RUNNER_TEMP/expected-paths.txt" - diff -u "$RUNNER_TEMP/expected-paths.txt" "$RUNNER_TEMP/changed-paths.txt" - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -- package-lock.json CHANGELOG.md .github/workflows/repair-nanoid-lockfile.yml - git commit -m "fix(deps): remediate nanoid 3.3.18" - git push origin "HEAD:${GITHUB_REF_NAME}" diff --git a/CHANGELOG.md b/CHANGELOG.md index bc816fae3..f070de880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,8 @@ ## Unreleased - 읽기 전용 `operations:runner-assignment` audit를 추가해 exact workflow run/source head에 대한 runner assignment를 완전 pagination으로 진단하고, 신선한 unassigned queue는 bounded grace 이후 실패-폐쇄한다. 이 증빙은 runner assignment와 required Check/CI, formal review, merge, release, deployment authority를 분리하며 assigned runner 이후 workflow failure를 성공으로 승격하지 않는다. - coordinated vulnerability disclosure 정책과 evidence-preserving vulnerability handling lifecycle, read-only private-vulnerability-reporting setting audit를 추가한다. 이 source 변경은 live private reporting 활성화·notification staffing·end-to-end advisory exercise·release/deployment authority를 증명하지 않는다. -- 개발 의존성 체인의 transitive `nanoid` lockfile resolution을 `3.3.16`에서 `3.3.17`로 최소 갱신하여 GHSA-2v37-7h3g-55p8 / CVE-2026-67213 보안 게이트를 복구한다. PostCSS의 선언 범위 `^3.3.16`과 다른 package metadata는 변경하지 않으며 audit waiver·ignore·severity 완화 없이 `npm ci`/`npm audit --audit-level=high`가 exact head에서 재검증되도록 유지한다. -- lockfile 재생성 도구 체인을 Node.js 24.19.0/npm 11.17.0으로 정확히 고정하고, `strict-allow-scripts=true` 아래 승인된 install-script identity만 실행하며 schema v3 exact-base lockfile change control로 package metadata drift를 실패-폐쇄한다. exact package before/after digest에 더해 top-level metadata digest와 대규모 package-set bulk evidence를 결합하며, #76의 `nanoid@3.3.17` 보안 수정과 explicit `npm ci --legacy-peer-deps=false --install-links=false` 계약을 보존한다. package-manager/toolchain·install-script authority·vulnerability audit·review/merge authority는 별도 증거 계층으로 유지한다. +- 개발 의존성 체인의 transitive `nanoid` lockfile resolution을 `3.3.17`에서 `3.3.18`로 최소 갱신하여 GHSA-2v37-7h3g-55p8 / CVE-2026-67213 보안 게이트를 복구한다. PostCSS의 선언 범위 `^3.3.16`과 다른 package metadata는 변경하지 않으며 audit waiver·ignore·severity 완화 없이 `npm ci`/`npm audit --audit-level=high`가 exact head에서 재검증되도록 유지한다. +- lockfile 재생성 도구 체인을 Node.js 24.19.0/npm 11.17.0으로 정확히 고정하고, `strict-allow-scripts=true` 아래 승인된 install-script identity만 실행하며 schema v3 exact-base lockfile change control로 package metadata drift를 실패-폐쇄한다. exact package before/after digest에 더해 top-level metadata digest와 대규모 package-set bulk evidence를 결합하며, 선행 `nanoid@3.3.18` 보안 수정과 explicit `npm ci --legacy-peer-deps=false --install-links=false` 계약을 보존한다. package-manager/toolchain·install-script authority·vulnerability audit·review/merge authority는 별도 증거 계층으로 유지한다. - `hourly-product-development`가 `NVIDIA_NIM_API_KEY`뿐 아니라 `NOEMA_MAINTAINER_APP_CLIENT_ID`와 `NOEMA_MAINTAINER_APP_PRIVATE_KEY` 존재를 checkout·OpenCode 설치·NVIDIA 호출 전에 검증한다. 게시 경로가 준비되지 않았으면 `maintainer_app_unavailable`로 실패 폐쇄하여 알려진 실패에 추론 비용을 쓰지 않으며, `dry_run`은 credential 없이 queue와 task contract를 검토하는 경로로 유지한다. 기존 reviewer App 및 `NOEMA_LLM_API_KEY`·`contextual-orchestrator` reviewer credential 경계는 변경하지 않는다. - zero open pull requests일 때만 `NVIDIA_NIM_API_KEY` 전용 OpenCode 1.17.13 세션을 실행하는 proposal-only `hourly-product-development` 루프를 추가. minute-47 schedule·non-cancelling single flight·OpenCode binary SHA-256 pin·NVIDIA NIM model fallback·후보 실패 시 clean reset·GitHub/OIDC credential 제거·reviewer key 비참조·full release verification·40-file/500,000-byte proposal budget·trusted one-PR packaging을 강제한다. 각 후보 실행은 900초와 30초 kill grace로 제한하고, 실패 후 `npm ci --ignore-scripts` 재설치는 별도 60초와 10초 kill grace로 제한한다. 재설치가 실패하거나 시간 초과되면 불완전한 dependency tree로 다음 후보를 실행하지 않고 실패 폐쇄한다. 세 후보의 실행·종료 2,790초, 두 번의 후보 간 재설치 140초, 300초 setup/diagnostic reserve를 합친 3,230초가 55분(3,300초) job budget에 들어가며 70초 여유를 남긴다. 마지막 후보가 실패하면 불필요한 reset·clean·재설치를 생략하고 안정적인 전체 후보 실패 진단으로 곧바로 종료한다. 모델 실행, 제안 코드 검증, publication credential을 각각 별도의 GitHub-hosted runner로 분리하고, immutable artifact의 exact ID·workflow-run ID·archive digest와 patch SHA-256·base SHA·file/byte count를 교차 검증하며 symlink(`120000`)와 gitlink(`160000`)를 세 경계 모두에서 차단한다. 제안 코드를 실행한 runner에는 Maintainer App secret/token을 절대 제공하지 않고, 세 번째 non-executing publisher에서만 late-bound repository-scoped App token을 발급한다. merge/release/deploy authority는 기존 `hourly-commercial-readiness` exact-head governance에 유지하며, 운영 Runbook과 OpenCode/NVIDIA/GitHub Actions/NIST SP 800-218 근거를 APA 7th doctoring에 기록했다. package version은 release·deployment·production KPI evidence를 발행하지 않으므로 유지한다. - `/health` liveness와 분리된 unauthenticated `GET`/`HEAD /ready` runtime readiness endpoint를 추가. GitHub Actions OIDC issuer·audience·organization/workflow binding·exact workflow ref·GitHub Cloud API origin·GitHub App identifiers·PKCS#8 private key를 외부 호출 없이 검증하며, 불완전한 설정은 secret/config value를 반사하지 않는 deterministic failure codes와 `503 ERR_SERVICE_NOT_READY`, `Retry-After`, no-store/nosniff/trace/latency headers로 실패-폐쇄한다. exact workflow named ref는 Git `check-ref-format`의 모호성·유효성 경계(`..`, `//`, dot-leading/`.lock` component, revision-expression 문자, trailing dot/slash 등)를 만족해야 하므로 GitHub가 실제로 표현할 수 없는 ref에서 false-ready가 발생하지 않는다. 배포 smoke contract가 liveness·runtime readiness·unauthenticated exchange challenge를 모두 요구하도록 확장하고 Kubernetes probe separation, RFC 9110, NIST SSDF, Git ref-format 근거를 APA 7th doctoring에 기록했다. diff --git a/package-lock.json b/package-lock.json index 62d47528f..91da46972 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2369,9 +2369,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.17", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", - "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { From 573069c38a5936264d75f7efe87ca2d728bcca17 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:12:44 +0900 Subject: [PATCH 4/5] test(security): bind nanoid 3.3.18 registry identity --- test/package-manager-predecessor-integration.test.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/package-manager-predecessor-integration.test.ts b/test/package-manager-predecessor-integration.test.ts index 564876288..7e5130e46 100644 --- a/test/package-manager-predecessor-integration.test.ts +++ b/test/package-manager-predecessor-integration.test.ts @@ -11,12 +11,17 @@ const packageJson = JSON.parse(readFileSync("package.json", "utf8")) as { }; const ciWorkflow = readFileSync(".github/workflows/ci.yml", "utf8"); const packageLock = JSON.parse(readFileSync("package-lock.json", "utf8")) as { - packages?: Record; + packages?: Record; }; describe("deterministic package-manager work integrated after the nanoid predecessor", () => { it("preserves the predecessor security remediation while pinning the reviewed toolchain", () => { - expect(packageLock.packages?.["node_modules/nanoid"]?.version).toBe("3.3.18"); + expect(packageLock.packages?.["node_modules/nanoid"]).toMatchObject({ + version: "3.3.18", + resolved: "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + integrity: + "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + }); expect(packageJson.packageManager).toBe("npm@11.17.0"); expect(packageJson.devEngines?.runtime).toEqual({ name: "node", @@ -47,4 +52,4 @@ describe("deterministic package-manager work integrated after the nanoid predece expect(ciWorkflow).toContain("name: refuse pull-request base drift after verification"); expect(ciWorkflow).toContain("npm ci --legacy-peer-deps=false --install-links=false"); }); -}); +}); \ No newline at end of file From 53915fbd8f316c0de8f2834554ef29338cec9d6e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 17:18:48 +0900 Subject: [PATCH 5/5] security(deps): authorize exact nanoid lock transition --- .github/lockfile-change-policy.json | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/lockfile-change-policy.json diff --git a/.github/lockfile-change-policy.json b/.github/lockfile-change-policy.json new file mode 100644 index 000000000..ece397d4f --- /dev/null +++ b/.github/lockfile-change-policy.json @@ -0,0 +1,23 @@ +{ + "baseSha": "6bc8ed016dc07f95d4e041a3b79ac00c4086b182", + "bulkChange": null, + "justification": "Remediate GHSA-2v37-7h3g-55p8 by advancing the single transitive nanoid package-lock node from 3.3.17 to the patched 3.3.18 release. Preserve all top-level lock metadata, PostCSS dependency declarations, and unrelated package nodes.", + "packageDigests": { + "node_modules/nanoid": { + "afterSha256": "d05f52cccf4bb2b3faa241c82560bdff38872191f8c2fc9e0fe11d1863c6689c", + "beforeSha256": "eb31926c2b062d6831f465580d52d350ebd0ec8cb0ae8c9b36a92e1bec871af4" + } + }, + "schemaVersion": 3, + "sources": [ + "https://github.com/advisories/GHSA-2v37-7h3g-55p8", + "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz" + ], + "targetPackages": [ + "node_modules/nanoid" + ], + "topLevelMetadataDigests": { + "afterSha256": "354c77096d1795b6f33b903ac8b54c3922a045279413f3e8681c78c1fe5278b1", + "beforeSha256": "354c77096d1795b6f33b903ac8b54c3922a045279413f3e8681c78c1fe5278b1" + } +} \ No newline at end of file