From cf014e8441e8ffbe8b41d93585ceb5c1a3d5bd4a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 6 Aug 2026 18:26:38 +0900 Subject: [PATCH 01/19] test(coverage): specify nested npm metadata lock validation --- ...rialize-npm-nested-metadata-validation.yml | 579 ++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 .github/workflows/materialize-npm-nested-metadata-validation.yml diff --git a/.github/workflows/materialize-npm-nested-metadata-validation.yml b/.github/workflows/materialize-npm-nested-metadata-validation.yml new file mode 100644 index 000000000..9ba0b0942 --- /dev/null +++ b/.github/workflows/materialize-npm-nested-metadata-validation.yml @@ -0,0 +1,579 @@ +name: Materialize nested npm metadata lock validation + +on: + push: + branches: [fix/npm-nested-metadata-lock-validation] + paths: + - .github/workflows/materialize-npm-nested-metadata-validation.yml + +permissions: + contents: read + +concurrency: + group: materialize-npm-nested-metadata-validation + cancel-in-progress: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + PYTHONWARNINGS: error + +jobs: + test-repair-verify: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.actor == 'seonghobae' && + github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact test-first head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.14' + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Add npm-v3 nested metadata regressions + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + from textwrap import dedent + + path = Path('tests/test_materialize_base_javascript_packages.py') + source = path.read_text(encoding='utf-8') + marker = 'def test_accepts_nested_metadata_only_npm_package_with_canonical_pin(' + if marker in source: + raise SystemExit('nested npm metadata tests already exist unexpectedly') + tests = dedent( + r''' + + + def _validate_changed_npm_packages(packages: dict[str, object]) -> None: + """Validate one synthetic npm v3 packages map through the public boundary.""" + + materializer.validate_head_npm_lock( + "package-lock.json", + ( + json.dumps({"lockfileVersion": 3, "packages": packages}) + "\n" + ).encode(), + ) + + + def _registry_metadata( + *, + version: str = "19.2.3", + package_name: str = "@types/react-dom", + integrity_character: str = "A", + ) -> dict[str, str]: + """Return one exact npm-registry tarball and SHA-512 metadata record.""" + + tarball_name = package_name.rsplit("/", 1)[-1] + return { + "version": version, + "resolved": ( + f"https://registry.npmjs.org/{package_name}/-/" + f"{tarball_name}-{version}.tgz" + ), + "integrity": "sha512-" + (integrity_character * 86) + "==", + } + + + def test_accepts_nested_metadata_only_npm_package_with_canonical_pin() -> None: + """A BandScope-shaped peer entry inherits one exact canonical registry pin.""" + + _validate_changed_npm_packages( + { + "node_modules/@types/react-dom": _registry_metadata(), + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "dev": True, + "peer": True, + }, + } + ) + + + @pytest.mark.parametrize( + ("packages", "message"), + [ + ( + { + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + } + }, + "must match one canonical registry package", + ), + ( + { + "node_modules/@types/react-dom": _registry_metadata( + version="19.2.4" + ), + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + }, + }, + "must match canonical package version", + ), + ( + { + "node_modules/@types/react-dom": { + **_registry_metadata(), + "resolved": "https://example.invalid/react-dom.tgz", + }, + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + }, + }, + "must resolve from https://registry.npmjs.org/", + ), + ( + { + "node_modules/@types/react-dom": { + **_registry_metadata(), + "integrity": "sha256-unsafe", + }, + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + }, + }, + "must use one SHA-512 integrity value", + ), + ( + { + "node_modules/@types/react-dom": _registry_metadata(), + "vendor/node_modules/@types/react-dom": _registry_metadata( + integrity_character="B" + ), + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + }, + }, + "must resolve to one unambiguous canonical registry package", + ), + ( + { + "node_modules/@types/react-dom": _registry_metadata(), + "apps/desktop/node_modules/@types/react-dom": { + "peer": True, + }, + }, + "must declare one exact version", + ), + ( + { + "node_modules/@types/react-dom": _registry_metadata(), + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": ( + "https://registry.npmjs.org/@types/react-dom/-/" + "react-dom-19.2.3.tgz" + ), + }, + }, + "must pin a registry tarball and SHA-512 integrity", + ), + ( + { + "node_modules/@types/react-dom": _registry_metadata(), + "apps/desktop/node_modules/@types": { + "version": "19.2.3", + "peer": True, + }, + }, + "has a malformed node_modules identity", + ), + ( + { + "node_modules": { + "version": "19.2.3", + "peer": True, + } + }, + "has a malformed node_modules identity", + ), + ( + { + "node_modules/@types/react-dom": { + "version": "19.2.3", + "peer": True, + } + }, + "must pin a registry tarball and SHA-512 integrity", + ), + ], + ) + def test_rejects_unbounded_nested_metadata_only_npm_package( + packages: dict[str, object], + message: str, + ) -> None: + """Nested metadata cannot weaken canonical identity, version, URL, or hash proof.""" + + with pytest.raises(ValueError, match=message): + _validate_changed_npm_packages(packages) + ''' + ) + path.write_text(source.rstrip() + tests + "\n", encoding='utf-8') + PY + git diff --check + + - name: Prove the compatibility regression is red + shell: bash --noprofile --norc {0} + run: | + set +e + python -m pytest -q \ + tests/test_materialize_base_javascript_packages.py::test_accepts_nested_metadata_only_npm_package_with_canonical_pin + status=$? + set -e + if [ "$status" -eq 0 ]; then + echo '::error::The nested metadata regression passed before production repair.' + exit 1 + fi + printf 'Observed expected pre-fix failure (exit %s).\n' "$status" + + - name: Apply fail-closed canonical-pin validation + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python - <<'PY' + from pathlib import Path + from textwrap import dedent + + path = Path('scripts/ci/materialize_base_javascript_packages.py') + source = path.read_text(encoding='utf-8') + start = source.index('def validate_head_npm_lock(') + end = source.index('\n\ndef materialize(', start) + replacement = dedent( + r''' + def _npm_package_identity(lock_path: str, package_path: str) -> str: + """Return the package identity after the final node_modules segment.""" + + parts = pathlib.PurePosixPath(package_path).parts + node_module_indexes = [ + index for index, part in enumerate(parts) if part == "node_modules" + ] + suffix = parts[node_module_indexes[-1] + 1 :] + if not suffix or (suffix[0].startswith("@") and len(suffix) < 2): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "has a malformed node_modules identity" + ) + if suffix[0].startswith("@"): + return f"{suffix[0]}/{suffix[1]}" + return suffix[0] + + + def _validated_npm_registry_pin( + lock_path: str, + package_path: str, + metadata: dict[str, Any], + ) -> tuple[str, str] | None: + """Return one validated registry pin or ``None`` for metadata-only input.""" + + has_resolved = "resolved" in metadata + has_integrity = "integrity" in metadata + if not has_resolved and not has_integrity: + return None + + resolved = metadata.get("resolved") + integrity = metadata.get("integrity") + if ( + not has_resolved + or not has_integrity + or not isinstance(resolved, str) + or not isinstance(integrity, str) + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must pin a registry tarball and SHA-512 integrity" + ) + parsed = urllib.parse.urlsplit(resolved) + try: + parsed_port = parsed.port + except ValueError as exc: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "has an invalid registry URL" + ) from exc + if ( + parsed.scheme != "https" + or parsed.hostname != NPM_REGISTRY_HOST + or parsed.username is not None + or parsed.password is not None + or parsed_port is not None + or parsed.query + or parsed.fragment + or not parsed.path.startswith("/") + or not parsed.path.endswith(".tgz") + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + f"must resolve from https://{NPM_REGISTRY_HOST}/" + ) + if not SHA512_SRI_RE.fullmatch(integrity): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must use one SHA-512 integrity value" + ) + return resolved, integrity + + + def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: + """Fail closed unless a changed HEAD npm lock is registry- and hash-bounded.""" + + try: + lock_data: Any = json.loads(lock_content.decode("utf-8")) + except (UnicodeDecodeError, json.JSONDecodeError) as exc: + raise ValueError( + f"current-head npm lock {lock_path} is invalid JSON: {exc}" + ) from exc + if not isinstance(lock_data, dict): + raise ValueError( + f"current-head npm lock {lock_path} must be a JSON object" + ) + lockfile_version = lock_data.get("lockfileVersion") + if ( + not isinstance(lockfile_version, int) + or isinstance(lockfile_version, bool) + or lockfile_version not in (2, 3) + ): + raise ValueError( + f"current-head npm lock {lock_path} must use " + "lockfileVersion 2 or 3" + ) + packages = lock_data.get("packages") + if not isinstance(packages, dict): + raise ValueError( + f"current-head npm lock {lock_path} must contain an " + "object-valued packages map" + ) + + registry_pins: dict[tuple[str, str], set[tuple[str, str]]] = {} + metadata_only_entries: list[tuple[str, str, str]] = [] + for package_path, metadata in sorted(packages.items()): + if not isinstance(package_path, str) or not isinstance(metadata, dict): + raise ValueError( + f"current-head npm lock {lock_path} contains malformed " + "package metadata" + ) + if "\\" in package_path: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe " + f"package path {package_path!r}" + ) + candidate = pathlib.PurePosixPath(package_path) + if candidate.is_absolute() or ".." in candidate.parts: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe " + f"package path {package_path!r}" + ) + if not package_path or "node_modules" not in candidate.parts: + continue + + resolved = metadata.get("resolved") + if metadata.get("link") is True: + if ( + not isinstance(resolved, str) + or not resolved + or "\\" in resolved + ): + raise ValueError( + f"current-head npm lock {lock_path} contains an " + f"unsafe workspace link for {package_path}" + ) + link_target = pathlib.PurePosixPath(resolved) + if ( + link_target.is_absolute() + or ".." in link_target.parts + or "node_modules" in link_target.parts + ): + raise ValueError( + f"current-head npm lock {lock_path} contains an " + f"unsafe workspace link for {package_path}" + ) + continue + + package_identity = _npm_package_identity(lock_path, package_path) + registry_pin = _validated_npm_registry_pin( + lock_path, package_path, metadata + ) + version = metadata.get("version") + if registry_pin is None: + if package_path == f"node_modules/{package_identity}": + raise ValueError( + f"current-head npm lock {lock_path} package " + f"{package_path} must pin a registry tarball and " + "SHA-512 integrity" + ) + if not isinstance(version, str) or not version: + raise ValueError( + f"current-head npm lock {lock_path} package " + f"{package_path} must declare one exact version" + ) + metadata_only_entries.append( + (package_path, package_identity, version) + ) + continue + + if isinstance(version, str) and version: + registry_pins.setdefault( + (package_identity, version), set() + ).add(registry_pin) + + for package_path, package_identity, version in metadata_only_entries: + canonical_path = f"node_modules/{package_identity}" + canonical_metadata = packages.get(canonical_path) + if not isinstance(canonical_metadata, dict): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must match one canonical registry package" + ) + if canonical_metadata.get("version") != version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must match canonical package version" + ) + canonical_pin = _validated_npm_registry_pin( + lock_path, canonical_path, canonical_metadata + ) + if canonical_pin is None: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must match one canonical registry package" + ) + if registry_pins.get((package_identity, version), set()) != { + canonical_pin + }: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} " + "must resolve to one unambiguous canonical registry package" + ) + ''' + ).lstrip() + path.write_text(source[:start] + replacement + source[end:], encoding='utf-8') + PY + + cat > docs/doctoring/npm-nested-package-metadata.md <<'EOF' + # npm nested package metadata validation + + ## Decision + + Changed npm lockfiles remain fail-closed: every fetched artifact must still be + represented by one HTTPS `registry.npmjs.org` tarball and one SHA-512 SRI value. + npm v3 may additionally serialize a nested workspace or peer location with only + version and classification metadata. Such an entry is accepted only when it + points by exact package identity and version to one unambiguous canonical root + package entry carrying the complete validated registry pin. + + The validator rejects missing canonical entries, version drift, partial pin + fields, unsafe paths, invalid registry URLs or ports, invalid integrity values, + and conflicting complete pins for the same identity and version. It consumes the + lock unchanged after validation; it neither repairs nor invents dependency data. + + ## Modular boundary + + This rule belongs to the organization dependency-materialization control plane. + BandScope and other npm-workspace repositories keep one canonical root lock and + do not need repository-specific exceptions or duplicate nested lockfiles. + + ## Verification + + Permanent tests include the BandScope `@types/react-dom` shape and negative + missing-canonical, version-mismatch, ambiguous-pin, URL, integrity, partial-pin, + malformed-identity, and root-metadata cases. The central suite requires 100% + production statement and branch coverage plus complete production docstrings. + + ## References + + npm, Inc. (2026). *package-lock.json* (npm CLI version 11). npm Docs. + https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ + + npm, Inc. (2026). *npm ci* (npm CLI version 11). npm Docs. + https://docs.npmjs.com/cli/v11/commands/npm-ci/ + EOF + + python - <<'PY' + from pathlib import Path + + path = Path('CHANGELOG.md') + source = path.read_text(encoding='utf-8') + marker = '### Fixed\n\n' + addition = ( + '- Accept npm-v3 nested workspace and peer metadata only when one exact ' + 'canonical package entry proves the same identity and version with a ' + 'validated registry tarball and SHA-512 integrity, while rejecting missing ' + 'or ambiguous provenance.\n' + ) + if addition not in source: + if source.count(marker) != 1: + raise SystemExit('Unreleased Fixed marker is not unique') + source = source.replace(marker, marker + addition, 1) + path.write_text(source, encoding='utf-8') + PY + git diff --check + + - name: Verify focused and complete central quality contracts + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python -m pytest -q tests/test_materialize_base_javascript_packages.py + python -m coverage erase + python -m coverage run --branch -m pytest -q + python -m coverage report --show-missing --fail-under=100 + python -m interrogate --fail-under=100 scripts/ci + python -m compileall -q scripts tests + python -m ruff check \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py + git diff --check + + - name: Publish verified focused commit and remove materializer + shell: bash --noprofile --norc -e -o pipefail {0} + env: + BRANCH_NAME: fix/npm-nested-metadata-lock-validation + GITHUB_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + run: | + remote_url="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + remote_head="$(git ls-remote "$remote_url" "refs/heads/$BRANCH_NAME" | cut -f1)" + test "$remote_head" = "$EXPECTED_HEAD" + rm .github/workflows/materialize-npm-nested-metadata-validation.yml + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add -A + git diff --cached --check + actual="$(git diff --cached --name-only | sort)" + expected="$(printf '%s\n' \ + CHANGELOG.md \ + docs/doctoring/npm-nested-package-metadata.md \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py | sort)" + test "$actual" = "$expected" + git commit -m 'fix(coverage): validate nested npm metadata through canonical pins' + git push \ + --force-with-lease="refs/heads/${BRANCH_NAME}:${EXPECTED_HEAD}" \ + "$remote_url" "HEAD:refs/heads/$BRANCH_NAME" From 6032fa912e415cc122182e40e73cd83f09343097 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 08:51:21 +0900 Subject: [PATCH 02/19] ci: add nested npm materializer trigger --- ...igger-npm-nested-metadata-materializer.yml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/trigger-npm-nested-metadata-materializer.yml diff --git a/.github/workflows/trigger-npm-nested-metadata-materializer.yml b/.github/workflows/trigger-npm-nested-metadata-materializer.yml new file mode 100644 index 000000000..cbcbc0cea --- /dev/null +++ b/.github/workflows/trigger-npm-nested-metadata-materializer.yml @@ -0,0 +1,54 @@ +name: Trigger nested npm metadata materializer + +on: + push: + branches: [fix/npm-nested-metadata-lock-validation] + paths: + - ".github/npm-nested-metadata.trigger" + +permissions: + contents: read + +jobs: + trigger: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Check out exact trigger + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + + - name: Retrigger the reviewed materializer through a workflow-scoped token + env: + PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} + TARGET_BRANCH: fix/npm-nested-metadata-lock-validation + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + test -n "${PUSH_TOKEN:-}" + printf '\n# exact-head retrigger %s\n' "$GITHUB_SHA" >> \ + .github/workflows/materialize-npm-nested-metadata-validation.yml + rm -f \ + .github/workflows/trigger-npm-nested-metadata-materializer.yml \ + .github/npm-nested-metadata.trigger + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git commit -m "ci: retrigger nested npm metadata materializer" + echo "::add-mask::$PUSH_TOKEN" + git remote set-url origin "https://x-access-token:${PUSH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + git push --force-with-lease="refs/heads/${TARGET_BRANCH}:${GITHUB_SHA}" \ + origin "HEAD:refs/heads/${TARGET_BRANCH}" From 4b2fceea5cbbff929623fec85b371f7f0bbe2898 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 08:51:33 +0900 Subject: [PATCH 03/19] ci: trigger nested npm metadata materializer --- .github/npm-nested-metadata.trigger | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/npm-nested-metadata.trigger diff --git a/.github/npm-nested-metadata.trigger b/.github/npm-nested-metadata.trigger new file mode 100644 index 000000000..04b8aae79 --- /dev/null +++ b/.github/npm-nested-metadata.trigger @@ -0,0 +1 @@ +Trigger the workflow-scoped retrigger for the reviewed nested npm metadata materializer. From 202a91e38c5d75db0fbea5c7a6ddea775c5412b8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:44:37 +0900 Subject: [PATCH 04/19] ci: add PR 807 materializer blank-line repair --- .../repair-pr807-materializer-blankline.yml | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .github/workflows/repair-pr807-materializer-blankline.yml diff --git a/.github/workflows/repair-pr807-materializer-blankline.yml b/.github/workflows/repair-pr807-materializer-blankline.yml new file mode 100644 index 000000000..636799386 --- /dev/null +++ b/.github/workflows/repair-pr807-materializer-blankline.yml @@ -0,0 +1,99 @@ +name: Repair PR 807 materializer blank line + +on: + push: + branches: [fix/npm-nested-metadata-lock-validation] + paths: [.github/pr807-materializer.trigger] + +permissions: + contents: read + +jobs: + repair: + permissions: + contents: write + issues: write + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 + with: + egress-policy: audit + + - name: Check out exact trigger + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + + - name: Repair generated-test trailing whitespace and remove superseded trigger + shell: bash --noprofile --norc -e -o pipefail {0} + env: + EXPECTED_HEAD: ${{ github.sha }} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" + python3 - <<'PY' + from pathlib import Path + + path = Path('.github/workflows/materialize-npm-nested-metadata-validation.yml') + source = path.read_text(encoding='utf-8') + old = 'path.write_text(source.rstrip() + tests + "\\n", encoding="utf-8")' + new = 'path.write_text(source.rstrip() + tests.rstrip() + "\\n", encoding="utf-8")' + if source.count(old) != 1: + raise SystemExit(f'materializer append anchor count={source.count(old)}') + path.write_text(source.replace(old, new, 1), encoding='utf-8') + PY + rm -f \ + .github/npm-nested-metadata.trigger \ + .github/pr807-materializer.trigger \ + .github/workflows/trigger-npm-nested-metadata-materializer.yml \ + .github/workflows/repair-pr807-materializer-blankline.yml + git diff --check + + - name: Create immutable corrected materializer commit + shell: bash --noprofile --norc -e -o pipefail {0} + env: + API_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + run: | + python3 - <<'PY' | tee "${RUNNER_TEMP}/pr807-materializer.txt" + import base64, json, os, subprocess, urllib.request + from pathlib import Path + repository='ContextualWisdomLab/.github' + parent=os.environ['EXPECTED_HEAD'] + token=os.environ['API_TOKEN'] + root=f'https://api.github.com/repos/{repository}' + expected={'.github/npm-nested-metadata.trigger','.github/pr807-materializer.trigger','.github/workflows/trigger-npm-nested-metadata-materializer.yml','.github/workflows/repair-pr807-materializer-blankline.yml','.github/workflows/materialize-npm-nested-metadata-validation.yml'} + def request(method, endpoint, payload=None): + req=urllib.request.Request(root+endpoint,data=None if payload is None else json.dumps(payload).encode(),method=method,headers={'Accept':'application/vnd.github+json','Authorization':f'Bearer {token}','X-GitHub-Api-Version':'2022-11-28','User-Agent':'cwl-pr807-materializer-repair'}) + with urllib.request.urlopen(req,timeout=60) as response: return json.load(response) + raw=subprocess.check_output(['git','diff','--name-status','-z','HEAD']).decode().split('\0') + changes=[]; index=0 + while index < len(raw)-1: + changes.append((raw[index],raw[index+1])); index += 2 + actual={path for _,path in changes} + if actual != expected: raise SystemExit(f'path mismatch missing={sorted(expected-actual)} extra={sorted(actual-expected)}') + parent_obj=request('GET',f'/git/commits/{parent}') + entries=[] + for status,path in changes: + if status == 'D': entries.append({'path':path,'mode':'100644','type':'blob','sha':None}) + else: + blob=request('POST','/git/blobs',{'content':base64.b64encode(Path(path).read_bytes()).decode(),'encoding':'base64'}) + entries.append({'path':path,'mode':'100644','type':'blob','sha':blob['sha']}) + tree=request('POST','/git/trees',{'base_tree':parent_obj['tree']['sha'],'tree':entries}) + commit=request('POST','/git/commits',{'message':'ci: remove trailing blank line from generated npm tests','tree':tree['sha'],'parents':[parent]}) + print('PR807_MATERIALIZER_PARENT_SHA='+parent) + print('PR807_MATERIALIZER_COMMIT_SHA='+commit['sha']) + PY + + - name: Publish corrected materializer pointer + shell: bash --noprofile --norc -e -o pipefail {0} + env: + GH_TOKEN: ${{ github.token }} + EXPECTED_HEAD: ${{ github.sha }} + run: | + commit_sha="$(sed -n 's/^PR807_MATERIALIZER_COMMIT_SHA=//p' "${RUNNER_TEMP}/pr807-materializer.txt")" + test "${#commit_sha}" -eq 40 + gh api --method POST repos/ContextualWisdomLab/.github/issues/807/comments -f "body=PR807_MATERIALIZER_PARENT_SHA=${EXPECTED_HEAD}%0APR807_MATERIALIZER_COMMIT_SHA=${commit_sha}" From de6e8b0dc11f9de16265ee198c28262ae9fc69fe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:44:46 +0900 Subject: [PATCH 05/19] ci: trigger PR 807 materializer repair --- .github/pr807-materializer.trigger | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/pr807-materializer.trigger diff --git a/.github/pr807-materializer.trigger b/.github/pr807-materializer.trigger new file mode 100644 index 000000000..0b73177ee --- /dev/null +++ b/.github/pr807-materializer.trigger @@ -0,0 +1 @@ +Trigger the bounded trailing-blank-line repair for the nested npm metadata materializer. From 3136fc735edfe3c64e0a6932b152e5a3c4560d5a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:53:23 +0900 Subject: [PATCH 06/19] chore(coverage): remove npm metadata materializer trigger --- .github/npm-nested-metadata.trigger | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/npm-nested-metadata.trigger diff --git a/.github/npm-nested-metadata.trigger b/.github/npm-nested-metadata.trigger deleted file mode 100644 index 04b8aae79..000000000 --- a/.github/npm-nested-metadata.trigger +++ /dev/null @@ -1 +0,0 @@ -Trigger the workflow-scoped retrigger for the reviewed nested npm metadata materializer. From f1439a7af918aab1a3f200436cb12a3b314a4e5a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:53:45 +0900 Subject: [PATCH 07/19] chore(coverage): remove PR 807 repair trigger --- .github/pr807-materializer.trigger | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/pr807-materializer.trigger diff --git a/.github/pr807-materializer.trigger b/.github/pr807-materializer.trigger deleted file mode 100644 index 0b73177ee..000000000 --- a/.github/pr807-materializer.trigger +++ /dev/null @@ -1 +0,0 @@ -Trigger the bounded trailing-blank-line repair for the nested npm metadata materializer. From 7a3221ef153b7640018ae8910e7ce9423857539b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:54:08 +0900 Subject: [PATCH 08/19] chore(coverage): remove npm metadata materializer workflow --- ...rialize-npm-nested-metadata-validation.yml | 579 ------------------ 1 file changed, 579 deletions(-) delete mode 100644 .github/workflows/materialize-npm-nested-metadata-validation.yml diff --git a/.github/workflows/materialize-npm-nested-metadata-validation.yml b/.github/workflows/materialize-npm-nested-metadata-validation.yml deleted file mode 100644 index 9ba0b0942..000000000 --- a/.github/workflows/materialize-npm-nested-metadata-validation.yml +++ /dev/null @@ -1,579 +0,0 @@ -name: Materialize nested npm metadata lock validation - -on: - push: - branches: [fix/npm-nested-metadata-lock-validation] - paths: - - .github/workflows/materialize-npm-nested-metadata-validation.yml - -permissions: - contents: read - -concurrency: - group: materialize-npm-nested-metadata-validation - cancel-in-progress: false - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - PYTHONWARNINGS: error - -jobs: - test-repair-verify: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.actor == 'seonghobae' && - github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 60 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact test-first head - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.14' - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Add npm-v3 nested metadata regressions - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - from textwrap import dedent - - path = Path('tests/test_materialize_base_javascript_packages.py') - source = path.read_text(encoding='utf-8') - marker = 'def test_accepts_nested_metadata_only_npm_package_with_canonical_pin(' - if marker in source: - raise SystemExit('nested npm metadata tests already exist unexpectedly') - tests = dedent( - r''' - - - def _validate_changed_npm_packages(packages: dict[str, object]) -> None: - """Validate one synthetic npm v3 packages map through the public boundary.""" - - materializer.validate_head_npm_lock( - "package-lock.json", - ( - json.dumps({"lockfileVersion": 3, "packages": packages}) + "\n" - ).encode(), - ) - - - def _registry_metadata( - *, - version: str = "19.2.3", - package_name: str = "@types/react-dom", - integrity_character: str = "A", - ) -> dict[str, str]: - """Return one exact npm-registry tarball and SHA-512 metadata record.""" - - tarball_name = package_name.rsplit("/", 1)[-1] - return { - "version": version, - "resolved": ( - f"https://registry.npmjs.org/{package_name}/-/" - f"{tarball_name}-{version}.tgz" - ), - "integrity": "sha512-" + (integrity_character * 86) + "==", - } - - - def test_accepts_nested_metadata_only_npm_package_with_canonical_pin() -> None: - """A BandScope-shaped peer entry inherits one exact canonical registry pin.""" - - _validate_changed_npm_packages( - { - "node_modules/@types/react-dom": _registry_metadata(), - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "dev": True, - "peer": True, - }, - } - ) - - - @pytest.mark.parametrize( - ("packages", "message"), - [ - ( - { - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - } - }, - "must match one canonical registry package", - ), - ( - { - "node_modules/@types/react-dom": _registry_metadata( - version="19.2.4" - ), - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - }, - }, - "must match canonical package version", - ), - ( - { - "node_modules/@types/react-dom": { - **_registry_metadata(), - "resolved": "https://example.invalid/react-dom.tgz", - }, - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - }, - }, - "must resolve from https://registry.npmjs.org/", - ), - ( - { - "node_modules/@types/react-dom": { - **_registry_metadata(), - "integrity": "sha256-unsafe", - }, - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - }, - }, - "must use one SHA-512 integrity value", - ), - ( - { - "node_modules/@types/react-dom": _registry_metadata(), - "vendor/node_modules/@types/react-dom": _registry_metadata( - integrity_character="B" - ), - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - }, - }, - "must resolve to one unambiguous canonical registry package", - ), - ( - { - "node_modules/@types/react-dom": _registry_metadata(), - "apps/desktop/node_modules/@types/react-dom": { - "peer": True, - }, - }, - "must declare one exact version", - ), - ( - { - "node_modules/@types/react-dom": _registry_metadata(), - "apps/desktop/node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": ( - "https://registry.npmjs.org/@types/react-dom/-/" - "react-dom-19.2.3.tgz" - ), - }, - }, - "must pin a registry tarball and SHA-512 integrity", - ), - ( - { - "node_modules/@types/react-dom": _registry_metadata(), - "apps/desktop/node_modules/@types": { - "version": "19.2.3", - "peer": True, - }, - }, - "has a malformed node_modules identity", - ), - ( - { - "node_modules": { - "version": "19.2.3", - "peer": True, - } - }, - "has a malformed node_modules identity", - ), - ( - { - "node_modules/@types/react-dom": { - "version": "19.2.3", - "peer": True, - } - }, - "must pin a registry tarball and SHA-512 integrity", - ), - ], - ) - def test_rejects_unbounded_nested_metadata_only_npm_package( - packages: dict[str, object], - message: str, - ) -> None: - """Nested metadata cannot weaken canonical identity, version, URL, or hash proof.""" - - with pytest.raises(ValueError, match=message): - _validate_changed_npm_packages(packages) - ''' - ) - path.write_text(source.rstrip() + tests + "\n", encoding='utf-8') - PY - git diff --check - - - name: Prove the compatibility regression is red - shell: bash --noprofile --norc {0} - run: | - set +e - python -m pytest -q \ - tests/test_materialize_base_javascript_packages.py::test_accepts_nested_metadata_only_npm_package_with_canonical_pin - status=$? - set -e - if [ "$status" -eq 0 ]; then - echo '::error::The nested metadata regression passed before production repair.' - exit 1 - fi - printf 'Observed expected pre-fix failure (exit %s).\n' "$status" - - - name: Apply fail-closed canonical-pin validation - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python - <<'PY' - from pathlib import Path - from textwrap import dedent - - path = Path('scripts/ci/materialize_base_javascript_packages.py') - source = path.read_text(encoding='utf-8') - start = source.index('def validate_head_npm_lock(') - end = source.index('\n\ndef materialize(', start) - replacement = dedent( - r''' - def _npm_package_identity(lock_path: str, package_path: str) -> str: - """Return the package identity after the final node_modules segment.""" - - parts = pathlib.PurePosixPath(package_path).parts - node_module_indexes = [ - index for index, part in enumerate(parts) if part == "node_modules" - ] - suffix = parts[node_module_indexes[-1] + 1 :] - if not suffix or (suffix[0].startswith("@") and len(suffix) < 2): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "has a malformed node_modules identity" - ) - if suffix[0].startswith("@"): - return f"{suffix[0]}/{suffix[1]}" - return suffix[0] - - - def _validated_npm_registry_pin( - lock_path: str, - package_path: str, - metadata: dict[str, Any], - ) -> tuple[str, str] | None: - """Return one validated registry pin or ``None`` for metadata-only input.""" - - has_resolved = "resolved" in metadata - has_integrity = "integrity" in metadata - if not has_resolved and not has_integrity: - return None - - resolved = metadata.get("resolved") - integrity = metadata.get("integrity") - if ( - not has_resolved - or not has_integrity - or not isinstance(resolved, str) - or not isinstance(integrity, str) - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must pin a registry tarball and SHA-512 integrity" - ) - parsed = urllib.parse.urlsplit(resolved) - try: - parsed_port = parsed.port - except ValueError as exc: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "has an invalid registry URL" - ) from exc - if ( - parsed.scheme != "https" - or parsed.hostname != NPM_REGISTRY_HOST - or parsed.username is not None - or parsed.password is not None - or parsed_port is not None - or parsed.query - or parsed.fragment - or not parsed.path.startswith("/") - or not parsed.path.endswith(".tgz") - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - f"must resolve from https://{NPM_REGISTRY_HOST}/" - ) - if not SHA512_SRI_RE.fullmatch(integrity): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must use one SHA-512 integrity value" - ) - return resolved, integrity - - - def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: - """Fail closed unless a changed HEAD npm lock is registry- and hash-bounded.""" - - try: - lock_data: Any = json.loads(lock_content.decode("utf-8")) - except (UnicodeDecodeError, json.JSONDecodeError) as exc: - raise ValueError( - f"current-head npm lock {lock_path} is invalid JSON: {exc}" - ) from exc - if not isinstance(lock_data, dict): - raise ValueError( - f"current-head npm lock {lock_path} must be a JSON object" - ) - lockfile_version = lock_data.get("lockfileVersion") - if ( - not isinstance(lockfile_version, int) - or isinstance(lockfile_version, bool) - or lockfile_version not in (2, 3) - ): - raise ValueError( - f"current-head npm lock {lock_path} must use " - "lockfileVersion 2 or 3" - ) - packages = lock_data.get("packages") - if not isinstance(packages, dict): - raise ValueError( - f"current-head npm lock {lock_path} must contain an " - "object-valued packages map" - ) - - registry_pins: dict[tuple[str, str], set[tuple[str, str]]] = {} - metadata_only_entries: list[tuple[str, str, str]] = [] - for package_path, metadata in sorted(packages.items()): - if not isinstance(package_path, str) or not isinstance(metadata, dict): - raise ValueError( - f"current-head npm lock {lock_path} contains malformed " - "package metadata" - ) - if "\\" in package_path: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe " - f"package path {package_path!r}" - ) - candidate = pathlib.PurePosixPath(package_path) - if candidate.is_absolute() or ".." in candidate.parts: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe " - f"package path {package_path!r}" - ) - if not package_path or "node_modules" not in candidate.parts: - continue - - resolved = metadata.get("resolved") - if metadata.get("link") is True: - if ( - not isinstance(resolved, str) - or not resolved - or "\\" in resolved - ): - raise ValueError( - f"current-head npm lock {lock_path} contains an " - f"unsafe workspace link for {package_path}" - ) - link_target = pathlib.PurePosixPath(resolved) - if ( - link_target.is_absolute() - or ".." in link_target.parts - or "node_modules" in link_target.parts - ): - raise ValueError( - f"current-head npm lock {lock_path} contains an " - f"unsafe workspace link for {package_path}" - ) - continue - - package_identity = _npm_package_identity(lock_path, package_path) - registry_pin = _validated_npm_registry_pin( - lock_path, package_path, metadata - ) - version = metadata.get("version") - if registry_pin is None: - if package_path == f"node_modules/{package_identity}": - raise ValueError( - f"current-head npm lock {lock_path} package " - f"{package_path} must pin a registry tarball and " - "SHA-512 integrity" - ) - if not isinstance(version, str) or not version: - raise ValueError( - f"current-head npm lock {lock_path} package " - f"{package_path} must declare one exact version" - ) - metadata_only_entries.append( - (package_path, package_identity, version) - ) - continue - - if isinstance(version, str) and version: - registry_pins.setdefault( - (package_identity, version), set() - ).add(registry_pin) - - for package_path, package_identity, version in metadata_only_entries: - canonical_path = f"node_modules/{package_identity}" - canonical_metadata = packages.get(canonical_path) - if not isinstance(canonical_metadata, dict): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must match one canonical registry package" - ) - if canonical_metadata.get("version") != version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must match canonical package version" - ) - canonical_pin = _validated_npm_registry_pin( - lock_path, canonical_path, canonical_metadata - ) - if canonical_pin is None: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must match one canonical registry package" - ) - if registry_pins.get((package_identity, version), set()) != { - canonical_pin - }: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} " - "must resolve to one unambiguous canonical registry package" - ) - ''' - ).lstrip() - path.write_text(source[:start] + replacement + source[end:], encoding='utf-8') - PY - - cat > docs/doctoring/npm-nested-package-metadata.md <<'EOF' - # npm nested package metadata validation - - ## Decision - - Changed npm lockfiles remain fail-closed: every fetched artifact must still be - represented by one HTTPS `registry.npmjs.org` tarball and one SHA-512 SRI value. - npm v3 may additionally serialize a nested workspace or peer location with only - version and classification metadata. Such an entry is accepted only when it - points by exact package identity and version to one unambiguous canonical root - package entry carrying the complete validated registry pin. - - The validator rejects missing canonical entries, version drift, partial pin - fields, unsafe paths, invalid registry URLs or ports, invalid integrity values, - and conflicting complete pins for the same identity and version. It consumes the - lock unchanged after validation; it neither repairs nor invents dependency data. - - ## Modular boundary - - This rule belongs to the organization dependency-materialization control plane. - BandScope and other npm-workspace repositories keep one canonical root lock and - do not need repository-specific exceptions or duplicate nested lockfiles. - - ## Verification - - Permanent tests include the BandScope `@types/react-dom` shape and negative - missing-canonical, version-mismatch, ambiguous-pin, URL, integrity, partial-pin, - malformed-identity, and root-metadata cases. The central suite requires 100% - production statement and branch coverage plus complete production docstrings. - - ## References - - npm, Inc. (2026). *package-lock.json* (npm CLI version 11). npm Docs. - https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ - - npm, Inc. (2026). *npm ci* (npm CLI version 11). npm Docs. - https://docs.npmjs.com/cli/v11/commands/npm-ci/ - EOF - - python - <<'PY' - from pathlib import Path - - path = Path('CHANGELOG.md') - source = path.read_text(encoding='utf-8') - marker = '### Fixed\n\n' - addition = ( - '- Accept npm-v3 nested workspace and peer metadata only when one exact ' - 'canonical package entry proves the same identity and version with a ' - 'validated registry tarball and SHA-512 integrity, while rejecting missing ' - 'or ambiguous provenance.\n' - ) - if addition not in source: - if source.count(marker) != 1: - raise SystemExit('Unreleased Fixed marker is not unique') - source = source.replace(marker, marker + addition, 1) - path.write_text(source, encoding='utf-8') - PY - git diff --check - - - name: Verify focused and complete central quality contracts - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python -m pytest -q tests/test_materialize_base_javascript_packages.py - python -m coverage erase - python -m coverage run --branch -m pytest -q - python -m coverage report --show-missing --fail-under=100 - python -m interrogate --fail-under=100 scripts/ci - python -m compileall -q scripts tests - python -m ruff check \ - scripts/ci/materialize_base_javascript_packages.py \ - tests/test_materialize_base_javascript_packages.py - git diff --check - - - name: Publish verified focused commit and remove materializer - shell: bash --noprofile --norc -e -o pipefail {0} - env: - BRANCH_NAME: fix/npm-nested-metadata-lock-validation - GITHUB_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - run: | - remote_url="https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - remote_head="$(git ls-remote "$remote_url" "refs/heads/$BRANCH_NAME" | cut -f1)" - test "$remote_head" = "$EXPECTED_HEAD" - rm .github/workflows/materialize-npm-nested-metadata-validation.yml - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git add -A - git diff --cached --check - actual="$(git diff --cached --name-only | sort)" - expected="$(printf '%s\n' \ - CHANGELOG.md \ - docs/doctoring/npm-nested-package-metadata.md \ - scripts/ci/materialize_base_javascript_packages.py \ - tests/test_materialize_base_javascript_packages.py | sort)" - test "$actual" = "$expected" - git commit -m 'fix(coverage): validate nested npm metadata through canonical pins' - git push \ - --force-with-lease="refs/heads/${BRANCH_NAME}:${EXPECTED_HEAD}" \ - "$remote_url" "HEAD:refs/heads/$BRANCH_NAME" From cb1024bfd5e451bcad05bcb31844f885a31670ef Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:54:29 +0900 Subject: [PATCH 09/19] chore(coverage): remove PR 807 repair workflow --- .../repair-pr807-materializer-blankline.yml | 99 ------------------- 1 file changed, 99 deletions(-) delete mode 100644 .github/workflows/repair-pr807-materializer-blankline.yml diff --git a/.github/workflows/repair-pr807-materializer-blankline.yml b/.github/workflows/repair-pr807-materializer-blankline.yml deleted file mode 100644 index 636799386..000000000 --- a/.github/workflows/repair-pr807-materializer-blankline.yml +++ /dev/null @@ -1,99 +0,0 @@ -name: Repair PR 807 materializer blank line - -on: - push: - branches: [fix/npm-nested-metadata-lock-validation] - paths: [.github/pr807-materializer.trigger] - -permissions: - contents: read - -jobs: - repair: - permissions: - contents: write - issues: write - runs-on: ubuntu-24.04 - timeout-minutes: 15 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 - with: - egress-policy: audit - - - name: Check out exact trigger - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - with: - ref: ${{ github.sha }} - fetch-depth: 1 - persist-credentials: false - - - name: Repair generated-test trailing whitespace and remove superseded trigger - shell: bash --noprofile --norc -e -o pipefail {0} - env: - EXPECTED_HEAD: ${{ github.sha }} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_HEAD" - python3 - <<'PY' - from pathlib import Path - - path = Path('.github/workflows/materialize-npm-nested-metadata-validation.yml') - source = path.read_text(encoding='utf-8') - old = 'path.write_text(source.rstrip() + tests + "\\n", encoding="utf-8")' - new = 'path.write_text(source.rstrip() + tests.rstrip() + "\\n", encoding="utf-8")' - if source.count(old) != 1: - raise SystemExit(f'materializer append anchor count={source.count(old)}') - path.write_text(source.replace(old, new, 1), encoding='utf-8') - PY - rm -f \ - .github/npm-nested-metadata.trigger \ - .github/pr807-materializer.trigger \ - .github/workflows/trigger-npm-nested-metadata-materializer.yml \ - .github/workflows/repair-pr807-materializer-blankline.yml - git diff --check - - - name: Create immutable corrected materializer commit - shell: bash --noprofile --norc -e -o pipefail {0} - env: - API_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - run: | - python3 - <<'PY' | tee "${RUNNER_TEMP}/pr807-materializer.txt" - import base64, json, os, subprocess, urllib.request - from pathlib import Path - repository='ContextualWisdomLab/.github' - parent=os.environ['EXPECTED_HEAD'] - token=os.environ['API_TOKEN'] - root=f'https://api.github.com/repos/{repository}' - expected={'.github/npm-nested-metadata.trigger','.github/pr807-materializer.trigger','.github/workflows/trigger-npm-nested-metadata-materializer.yml','.github/workflows/repair-pr807-materializer-blankline.yml','.github/workflows/materialize-npm-nested-metadata-validation.yml'} - def request(method, endpoint, payload=None): - req=urllib.request.Request(root+endpoint,data=None if payload is None else json.dumps(payload).encode(),method=method,headers={'Accept':'application/vnd.github+json','Authorization':f'Bearer {token}','X-GitHub-Api-Version':'2022-11-28','User-Agent':'cwl-pr807-materializer-repair'}) - with urllib.request.urlopen(req,timeout=60) as response: return json.load(response) - raw=subprocess.check_output(['git','diff','--name-status','-z','HEAD']).decode().split('\0') - changes=[]; index=0 - while index < len(raw)-1: - changes.append((raw[index],raw[index+1])); index += 2 - actual={path for _,path in changes} - if actual != expected: raise SystemExit(f'path mismatch missing={sorted(expected-actual)} extra={sorted(actual-expected)}') - parent_obj=request('GET',f'/git/commits/{parent}') - entries=[] - for status,path in changes: - if status == 'D': entries.append({'path':path,'mode':'100644','type':'blob','sha':None}) - else: - blob=request('POST','/git/blobs',{'content':base64.b64encode(Path(path).read_bytes()).decode(),'encoding':'base64'}) - entries.append({'path':path,'mode':'100644','type':'blob','sha':blob['sha']}) - tree=request('POST','/git/trees',{'base_tree':parent_obj['tree']['sha'],'tree':entries}) - commit=request('POST','/git/commits',{'message':'ci: remove trailing blank line from generated npm tests','tree':tree['sha'],'parents':[parent]}) - print('PR807_MATERIALIZER_PARENT_SHA='+parent) - print('PR807_MATERIALIZER_COMMIT_SHA='+commit['sha']) - PY - - - name: Publish corrected materializer pointer - shell: bash --noprofile --norc -e -o pipefail {0} - env: - GH_TOKEN: ${{ github.token }} - EXPECTED_HEAD: ${{ github.sha }} - run: | - commit_sha="$(sed -n 's/^PR807_MATERIALIZER_COMMIT_SHA=//p' "${RUNNER_TEMP}/pr807-materializer.txt")" - test "${#commit_sha}" -eq 40 - gh api --method POST repos/ContextualWisdomLab/.github/issues/807/comments -f "body=PR807_MATERIALIZER_PARENT_SHA=${EXPECTED_HEAD}%0APR807_MATERIALIZER_COMMIT_SHA=${commit_sha}" From f428ccc6c9ec07bcd1fb69abbef5e8516ec5ca7e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 09:54:52 +0900 Subject: [PATCH 10/19] chore(coverage): remove npm metadata trigger workflow --- ...igger-npm-nested-metadata-materializer.yml | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 .github/workflows/trigger-npm-nested-metadata-materializer.yml diff --git a/.github/workflows/trigger-npm-nested-metadata-materializer.yml b/.github/workflows/trigger-npm-nested-metadata-materializer.yml deleted file mode 100644 index cbcbc0cea..000000000 --- a/.github/workflows/trigger-npm-nested-metadata-materializer.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Trigger nested npm metadata materializer - -on: - push: - branches: [fix/npm-nested-metadata-lock-validation] - paths: - - ".github/npm-nested-metadata.trigger" - -permissions: - contents: read - -jobs: - trigger: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Check out exact trigger - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - persist-credentials: false - - - name: Retrigger the reviewed materializer through a workflow-scoped token - env: - PUSH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - TARGET_BRANCH: fix/npm-nested-metadata-lock-validation - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test -n "${PUSH_TOKEN:-}" - printf '\n# exact-head retrigger %s\n' "$GITHUB_SHA" >> \ - .github/workflows/materialize-npm-nested-metadata-validation.yml - rm -f \ - .github/workflows/trigger-npm-nested-metadata-materializer.yml \ - .github/npm-nested-metadata.trigger - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "ci: retrigger nested npm metadata materializer" - echo "::add-mask::$PUSH_TOKEN" - git remote set-url origin "https://x-access-token:${PUSH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git push --force-with-lease="refs/heads/${TARGET_BRANCH}:${GITHUB_SHA}" \ - origin "HEAD:refs/heads/${TARGET_BRANCH}" From 9c298d709499bc3dc8f20aacbbce0f74f10f8d9e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:01:12 +0900 Subject: [PATCH 11/19] test(coverage): define canonical-pin contract for nested npm metadata --- ...est_npm_nested_metadata_lock_validation.py | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tests/test_npm_nested_metadata_lock_validation.py diff --git a/tests/test_npm_nested_metadata_lock_validation.py b/tests/test_npm_nested_metadata_lock_validation.py new file mode 100644 index 000000000..a2346606f --- /dev/null +++ b/tests/test_npm_nested_metadata_lock_validation.py @@ -0,0 +1,163 @@ +"""Contracts for npm v2/v3 metadata-only nested package locations.""" + +from __future__ import annotations + +import json + +import pytest + +from scripts.ci import materialize_base_javascript_packages as materializer + + +_VALID_INTEGRITY = "sha512-" + ("A" * 86) + "==" + + +def _pinned(version: str, package_name: str) -> dict[str, str]: + """Return one exact public-registry package pin.""" + + archive_name = package_name.rsplit("/", 1)[-1] + return { + "version": version, + "resolved": ( + f"https://registry.npmjs.org/{package_name}/-/" + f"{archive_name}-{version}.tgz" + ), + "integrity": _VALID_INTEGRITY, + } + + +def _lock(packages: dict[str, object]) -> bytes: + """Serialize one npm lock fixture as UTF-8 JSON bytes.""" + + return json.dumps( + {"lockfileVersion": 3, "packages": packages}, + sort_keys=True, + ).encode("utf-8") + + +def test_accepts_bandscope_scoped_metadata_through_exact_root_pin() -> None: + """A BandScope-shaped peer location may reuse one exact canonical pin.""" + + packages = { + "": {"name": "bandscope"}, + "node_modules/@types/react-dom": _pinned("19.1.7", "@types/react-dom"), + "apps/desktop/node_modules/@types/react-dom": { + "version": "19.1.7", + "dev": True, + "peer": True, + }, + } + + materializer.validate_head_npm_lock("package-lock.json", _lock(packages)) + + +def test_accepts_unscoped_metadata_and_independently_pinned_nested_version() -> None: + """Metadata reuse and an independently complete nested pin can coexist.""" + + packages = { + "node_modules/react": _pinned("19.1.1", "react"), + "apps/web/node_modules/react": {"version": "19.1.1", "peer": True}, + "node_modules/legacy/node_modules/react": _pinned("18.3.1", "react"), + } + + materializer.validate_head_npm_lock("package-lock.json", _lock(packages)) + + +@pytest.mark.parametrize( + ("packages", "message"), + [ + ( + {"apps/web/node_modules/react": {"version": "19.1.1"}}, + "canonical root pin", + ), + ( + { + "node_modules/react": _pinned("19.1.1", "react"), + "apps/web/node_modules/react": {"version": "19.1.0"}, + }, + "exact canonical version", + ), + ( + { + "node_modules/react": { + "version": "19.1.1", + "resolved": _pinned("19.1.1", "react")["resolved"], + }, + "apps/web/node_modules/react": {"version": "19.1.1"}, + }, + "registry tarball and SHA-512 integrity", + ), + ( + { + "node_modules/react": _pinned("19.1.1", "react"), + "apps/web/node_modules/react": { + "version": "19.1.1", + "resolved": _pinned("19.1.1", "react")["resolved"], + }, + }, + "must not partially declare", + ), + ( + { + "node_modules/react": _pinned("19.1.1", "react"), + "apps/web/node_modules/react": { + "version": "19.1.1", + "integrity": _VALID_INTEGRITY, + }, + }, + "must not partially declare", + ), + ( + { + "node_modules/react": { + **_pinned("19.1.1", "react"), + "resolved": "https://example.invalid/react-19.1.1.tgz", + }, + "apps/web/node_modules/react": {"version": "19.1.1"}, + }, + "must resolve from https://registry.npmjs.org/", + ), + ( + { + "node_modules/react": { + **_pinned("19.1.1", "react"), + "integrity": "sha512-invalid", + }, + "apps/web/node_modules/react": {"version": "19.1.1"}, + }, + "must use one SHA-512 integrity value", + ), + ( + {"apps/web/node_modules/@types": {"version": "1.0.0"}}, + "malformed npm package identity", + ), + ( + {"apps/web/node_modules/@types/react/extra": {"version": "1.0.0"}}, + "malformed npm package identity", + ), + ( + { + "node_modules/react": { + "version": "19.1.1", + "dev": True, + } + }, + "canonical root pin", + ), + ( + { + "node_modules/react": _pinned("19.1.1", "react"), + "apps/web/node_modules/react": {"version": ""}, + }, + "nonempty exact version", + ), + ], +) +def test_rejects_untrusted_metadata_only_nested_locations( + packages: dict[str, object], + message: str, +) -> None: + """Every metadata-only location must close through one exact safe root pin.""" + + with pytest.raises(ValueError, match=message): + materializer.validate_head_npm_lock("package-lock.json", _lock(packages)) From ae9d029c011a9e9a63f484b46a61e17462f86345 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:04:36 +0900 Subject: [PATCH 12/19] ci(coverage): add permanent nested npm metadata quality gate --- ...-nested-metadata-validation-quality-ci.yml | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .github/workflows/npm-nested-metadata-validation-quality-ci.yml diff --git a/.github/workflows/npm-nested-metadata-validation-quality-ci.yml b/.github/workflows/npm-nested-metadata-validation-quality-ci.yml new file mode 100644 index 000000000..b69b45ab1 --- /dev/null +++ b/.github/workflows/npm-nested-metadata-validation-quality-ci.yml @@ -0,0 +1,108 @@ +name: npm Nested Metadata Validation Quality CI + +on: + pull_request: + branches: [main] + paths: + - ".github/workflows/npm-nested-metadata-validation-quality-ci.yml" + - "scripts/ci/materialize_base_javascript_packages.py" + - "tests/test_materialize_base_javascript_packages.py" + - "tests/test_npm_nested_metadata_lock_validation.py" + - "docs/doctoring/npm-nested-metadata-canonical-pins.md" + - "requirements-opencode-review-ci-hashes.txt" + - "CHANGELOG.md" + push: + branches: [main] + paths: + - ".github/workflows/npm-nested-metadata-validation-quality-ci.yml" + - "scripts/ci/materialize_base_javascript_packages.py" + - "tests/test_materialize_base_javascript_packages.py" + - "tests/test_npm_nested_metadata_lock_validation.py" + - "docs/doctoring/npm-nested-metadata-canonical-pins.md" + - "requirements-opencode-review-ci-hashes.txt" + - "CHANGELOG.md" + +concurrency: + group: npm-nested-metadata-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + python-310-compatibility: + name: Python 3.10 compatibility + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout exact source revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Python 3.10 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.10" + - name: Compile implementation and contracts + run: | + python -m compileall -q \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + + python-314-quality: + name: Python 3.14 complete quality + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout exact source revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + - name: Install exact hash-locked quality tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + - name: Run focused tests with complete production branch coverage + run: | + python -m coverage erase + python -m coverage run --branch -m pytest -q \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + python -m coverage report \ + --include=scripts/ci/materialize_base_javascript_packages.py \ + --show-missing \ + --fail-under=100 + - name: Enforce complete production docstrings and compilation + run: | + python -m interrogate --fail-under 100 scripts/ci/materialize_base_javascript_packages.py + python -m compileall -q \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + - name: Run complete central regression suite + run: | + python -m coverage erase + python -m coverage run -m pytest tests -q + python -m coverage report --show-missing --fail-under=100 + - name: Verify clean patches + run: git diff --check From e1e075154854ee0f1458f64ab90181c5d550f2c8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:08:24 +0900 Subject: [PATCH 13/19] chore(coverage): implement nested npm metadata pins once --- .../pr807-implement-nested-metadata-once.yml | 353 ++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 .github/workflows/pr807-implement-nested-metadata-once.yml diff --git a/.github/workflows/pr807-implement-nested-metadata-once.yml b/.github/workflows/pr807-implement-nested-metadata-once.yml new file mode 100644 index 000000000..a32844425 --- /dev/null +++ b/.github/workflows/pr807-implement-nested-metadata-once.yml @@ -0,0 +1,353 @@ +name: PR 807 Implement Nested npm Metadata Once + +on: + push: + branches: + - fix/npm-nested-metadata-lock-validation + paths: + - .github/workflows/pr807-implement-nested-metadata-once.yml + +permissions: + contents: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + implement: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' + runs-on: ubuntu-24.04 + timeout-minutes: 35 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger head + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.sha }} + fetch-depth: 2 + persist-credentials: true + + - name: Refuse concurrent branch movement + env: + EXPECTED_SHA: ${{ github.sha }} + EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" + remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" + test "$remote_sha" = "$EXPECTED_SHA" + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Implement canonical-pin validation and documentation + run: | + python3 - <<'PY' + from pathlib import Path + + source_path = Path('scripts/ci/materialize_base_javascript_packages.py') + source = source_path.read_text(encoding='utf-8') + constant_anchor = 'SHA512_SRI_RE = re.compile(r"^sha512-[A-Za-z0-9+/]{86}==$")\n' + constant_replacement = constant_anchor + ( + 'NPM_PACKAGE_IDENTITY_RE = re.compile(\n' + ' r"^(?:@[a-z0-9][a-z0-9._~-]*/)?[a-z0-9][a-z0-9._~-]*$"\n' + ')\n' + ) + if source.count(constant_anchor) != 1: + raise SystemExit('npm identity constant anchor changed') + source = source.replace(constant_anchor, constant_replacement, 1) + + function_anchor = '\ndef validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None:\n' + helpers = r''' + +def _npm_package_identity(candidate: pathlib.PurePosixPath) -> str | None: + """Return the exact package identity after the final node_modules segment.""" + + positions = [ + index for index, segment in enumerate(candidate.parts) if segment == "node_modules" + ] + if not positions: + return None + tail = candidate.parts[positions[-1] + 1 :] + if len(tail) == 1 and not tail[0].startswith("@"): + identity = tail[0] + elif len(tail) == 2 and tail[0].startswith("@"): + identity = f"{tail[0]}/{tail[1]}" + else: + return None + return identity if NPM_PACKAGE_IDENTITY_RE.fullmatch(identity) else None + + +def _validate_npm_registry_pin( + lock_path: str, + package_path: str, + resolved: object, + integrity: object, +) -> None: + """Require one exact public npm tarball and SHA-512 integrity pair.""" + + if not isinstance(resolved, str) or not isinstance(integrity, str): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must pin a registry tarball and SHA-512 integrity" + ) + parsed = urllib.parse.urlsplit(resolved) + try: + parsed_port = parsed.port + except ValueError as exc: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has an invalid registry URL" + ) from exc + if ( + parsed.scheme != "https" + or parsed.hostname != NPM_REGISTRY_HOST + or parsed.username is not None + or parsed.password is not None + or parsed_port is not None + or parsed.query + or parsed.fragment + or not parsed.path.startswith("/") + or not parsed.path.endswith(".tgz") + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must resolve from https://{NPM_REGISTRY_HOST}/" + ) + if not SHA512_SRI_RE.fullmatch(integrity): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must use one SHA-512 integrity value" + ) + + +def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: +''' + if source.count(function_anchor) != 1: + raise SystemExit('validator function anchor changed') + source = source.replace(function_anchor, helpers, 1) + + loop_start = source.index(' for package_path, metadata in sorted(packages.items()):\n') + loop_end = source.index('\n\ndef materialize(\n', loop_start) + new_loop = r''' for package_path, metadata in sorted(packages.items()): + if not isinstance(package_path, str) or not isinstance(metadata, dict): + raise ValueError( + f"current-head npm lock {lock_path} contains malformed package metadata" + ) + if "\\" in package_path: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" + ) + candidate = pathlib.PurePosixPath(package_path) + if candidate.is_absolute() or ".." in candidate.parts: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" + ) + if not package_path or "node_modules" not in candidate.parts: + continue + + resolved = metadata.get("resolved") + if metadata.get("link") is True: + if not isinstance(resolved, str) or not resolved or "\\" in resolved: + raise ValueError( + f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" + ) + link_target = pathlib.PurePosixPath(resolved) + if ( + link_target.is_absolute() + or ".." in link_target.parts + or "node_modules" in link_target.parts + ): + raise ValueError( + f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" + ) + continue + + identity = _npm_package_identity(candidate) + if identity is None: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has a malformed npm package identity" + ) + + has_resolved = "resolved" in metadata + has_integrity = "integrity" in metadata + if has_resolved != has_integrity: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must not partially declare resolved or integrity" + ) + if has_resolved: + _validate_npm_registry_pin( + lock_path, + package_path, + metadata.get("resolved"), + metadata.get("integrity"), + ) + continue + + version = metadata.get("version") + if not isinstance(version, str) or not version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must declare a nonempty exact version" + ) + canonical_path = f"node_modules/{identity}" + if package_path == canonical_path: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must provide a canonical root pin" + ) + canonical_metadata = packages.get(canonical_path) + if ( + not isinstance(canonical_metadata, dict) + or canonical_metadata.get("link") is True + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" + ) + canonical_version = canonical_metadata.get("version") + if not isinstance(canonical_version, str) or not canonical_version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" + ) + if canonical_version != version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must match the exact canonical version at {canonical_path}" + ) + _validate_npm_registry_pin( + lock_path, + canonical_path, + canonical_metadata.get("resolved"), + canonical_metadata.get("integrity"), + ) +''' + source_path.write_text(source[:loop_start] + new_loop + source[loop_end:], encoding='utf-8') + + doctoring_path = Path('docs/doctoring/npm-nested-metadata-canonical-pins.md') + doctoring_path.parent.mkdir(parents=True, exist_ok=True) + doctoring_path.write_text('''# Canonical pins for metadata-only nested npm locations + +## Decision + +Changed-head npm lock validation continues to accept only lockfile versions 2 and +3, safe repository-relative package locations, safe workspace links, and exact +public-registry SHA-512 artifact pins. One narrowly defined npm serialization is +also accepted: a non-link nested `node_modules` location may omit `resolved` and +`integrity` only when it declares a nonempty exact `version` and the canonical +root location for the same normalized package identity supplies the same version, +one HTTPS `registry.npmjs.org` tarball, and one valid SHA-512 SRI value. + +For `apps/desktop/node_modules/@types/react-dom`, the only eligible canonical +location is `node_modules/@types/react-dom`. Scoped identity is derived from the +two segments after the final `node_modules`; an unscoped identity uses exactly +one segment. Missing, malformed, ambiguous, linked, version-mismatched, partially +pinned, non-registry, or invalid-integrity canonical evidence fails closed. +Complete nested pins remain independently valid and are not rebound to another +version. + +## Trust and interpretation boundary + +The validator consumes the original lock bytes unchanged. It does not repair, +resolve, install, fetch, infer a version range, or synthesize artifact metadata. +The canonical lookup is a structural provenance check for one lock document, not +a claim that arbitrary duplicated locations are interchangeable. Pull-request +code and lifecycle hooks remain outside the trusted materializer. + +npm documents `packages` as a location-keyed map and notes that descriptors may +contain version and classification metadata while artifact fields depend on the +resolved dependency form. npm workspaces are managed from one top-level package +and lock while nested packages are linked into the root installation. This +central policy is intentionally stricter: a metadata-only installed location is +accepted only through one exact root package identity, version, registry origin, +and SHA-512 integrity closure. + +## Verification + +Permanent tests include the BandScope scoped peer shape, an unscoped equivalent, +an independently pinned nested version, missing canonical metadata, version +mismatch, partial pins, hostile registry URLs, invalid SRI, malformed scoped and +unscoped identities, empty versions, and metadata-only root entries. Python 3.10 +compilation and Python 3.14 focused/full tests enforce complete production +statement, branch, and public-docstring coverage. + +## Rollback + +Rollback removes the canonical metadata-only branch and returns to rejecting all +non-link installed locations without local artifact fields. It must not weaken +URL, path, link, lock-version, SHA-512, immutable-source, or offline-execution +controls. + +## References + +npm, Inc. (2026). *package-lock.json*. npm Docs. +https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ + +npm, Inc. (2026). *Workspaces*. npm Docs. +https://docs.npmjs.com/cli/v11/using-npm/workspaces/ +''', encoding='utf-8') + + changelog_path = Path('CHANGELOG.md') + changelog = changelog_path.read_text(encoding='utf-8') + fixed_anchor = '### Fixed\n\n' + entry = ( + '- Accepted metadata-only nested npm v2/v3 package locations only when one ' + 'canonical root package has the same normalized identity and exact version ' + 'plus a validated public-registry tarball and SHA-512 integrity, while ' + 'retaining fail-closed path, link, partial-pin, origin, and SRI controls.\n' + ) + if changelog.count(fixed_anchor) != 1: + raise SystemExit('CHANGELOG Fixed anchor changed') + if entry not in changelog: + changelog = changelog.replace(fixed_anchor, fixed_anchor + entry, 1) + changelog_path.write_text(changelog, encoding='utf-8') + PY + git diff --check + + - name: Run focused and complete quality evidence + run: | + python -m coverage erase + python -m coverage run --branch -m pytest -q \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + python -m coverage report \ + --include=scripts/ci/materialize_base_javascript_packages.py \ + --show-missing \ + --fail-under=100 + python -m interrogate --fail-under 100 scripts/ci/materialize_base_javascript_packages.py + python -m compileall -q \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + python -m coverage erase + python -m coverage run -m pytest tests -q + python -m coverage report --show-missing --fail-under=100 + git diff --check + + - name: Commit permanent non-workflow implementation + env: + EXPECTED_SHA: ${{ github.sha }} + EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + run: | + remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" + test "$remote_sha" = "$EXPECTED_SHA" + expected="$(printf '%s\n' \ + 'CHANGELOG.md' \ + 'docs/doctoring/npm-nested-metadata-canonical-pins.md' \ + 'scripts/ci/materialize_base_javascript_packages.py' | sort)" + actual="$(git diff --name-only | sort)" + test "$actual" = "$expected" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add CHANGELOG.md \ + docs/doctoring/npm-nested-metadata-canonical-pins.md \ + scripts/ci/materialize_base_javascript_packages.py + git commit -m "fix(coverage): validate nested npm metadata through canonical pins" + test "$(git rev-parse HEAD^)" = "$EXPECTED_SHA" + git push origin "HEAD:refs/heads/$EXPECTED_BRANCH" From b6efc22eae2b4576caa8e63de94c55d7e3ee8540 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:10:26 +0900 Subject: [PATCH 14/19] chore(coverage): remove PR 807 implementation writer --- .../pr807-implement-nested-metadata-once.yml | 353 ------------------ 1 file changed, 353 deletions(-) delete mode 100644 .github/workflows/pr807-implement-nested-metadata-once.yml diff --git a/.github/workflows/pr807-implement-nested-metadata-once.yml b/.github/workflows/pr807-implement-nested-metadata-once.yml deleted file mode 100644 index a32844425..000000000 --- a/.github/workflows/pr807-implement-nested-metadata-once.yml +++ /dev/null @@ -1,353 +0,0 @@ -name: PR 807 Implement Nested npm Metadata Once - -on: - push: - branches: - - fix/npm-nested-metadata-lock-validation - paths: - - .github/workflows/pr807-implement-nested-metadata-once.yml - -permissions: - contents: write - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - implement: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' - runs-on: ubuntu-24.04 - timeout-minutes: 35 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger head - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - fetch-depth: 2 - persist-credentials: true - - - name: Refuse concurrent branch movement - env: - EXPECTED_SHA: ${{ github.sha }} - EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" - remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" - test "$remote_sha" = "$EXPECTED_SHA" - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Implement canonical-pin validation and documentation - run: | - python3 - <<'PY' - from pathlib import Path - - source_path = Path('scripts/ci/materialize_base_javascript_packages.py') - source = source_path.read_text(encoding='utf-8') - constant_anchor = 'SHA512_SRI_RE = re.compile(r"^sha512-[A-Za-z0-9+/]{86}==$")\n' - constant_replacement = constant_anchor + ( - 'NPM_PACKAGE_IDENTITY_RE = re.compile(\n' - ' r"^(?:@[a-z0-9][a-z0-9._~-]*/)?[a-z0-9][a-z0-9._~-]*$"\n' - ')\n' - ) - if source.count(constant_anchor) != 1: - raise SystemExit('npm identity constant anchor changed') - source = source.replace(constant_anchor, constant_replacement, 1) - - function_anchor = '\ndef validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None:\n' - helpers = r''' - -def _npm_package_identity(candidate: pathlib.PurePosixPath) -> str | None: - """Return the exact package identity after the final node_modules segment.""" - - positions = [ - index for index, segment in enumerate(candidate.parts) if segment == "node_modules" - ] - if not positions: - return None - tail = candidate.parts[positions[-1] + 1 :] - if len(tail) == 1 and not tail[0].startswith("@"): - identity = tail[0] - elif len(tail) == 2 and tail[0].startswith("@"): - identity = f"{tail[0]}/{tail[1]}" - else: - return None - return identity if NPM_PACKAGE_IDENTITY_RE.fullmatch(identity) else None - - -def _validate_npm_registry_pin( - lock_path: str, - package_path: str, - resolved: object, - integrity: object, -) -> None: - """Require one exact public npm tarball and SHA-512 integrity pair.""" - - if not isinstance(resolved, str) or not isinstance(integrity, str): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must pin a registry tarball and SHA-512 integrity" - ) - parsed = urllib.parse.urlsplit(resolved) - try: - parsed_port = parsed.port - except ValueError as exc: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has an invalid registry URL" - ) from exc - if ( - parsed.scheme != "https" - or parsed.hostname != NPM_REGISTRY_HOST - or parsed.username is not None - or parsed.password is not None - or parsed_port is not None - or parsed.query - or parsed.fragment - or not parsed.path.startswith("/") - or not parsed.path.endswith(".tgz") - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must resolve from https://{NPM_REGISTRY_HOST}/" - ) - if not SHA512_SRI_RE.fullmatch(integrity): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must use one SHA-512 integrity value" - ) - - -def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: -''' - if source.count(function_anchor) != 1: - raise SystemExit('validator function anchor changed') - source = source.replace(function_anchor, helpers, 1) - - loop_start = source.index(' for package_path, metadata in sorted(packages.items()):\n') - loop_end = source.index('\n\ndef materialize(\n', loop_start) - new_loop = r''' for package_path, metadata in sorted(packages.items()): - if not isinstance(package_path, str) or not isinstance(metadata, dict): - raise ValueError( - f"current-head npm lock {lock_path} contains malformed package metadata" - ) - if "\\" in package_path: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" - ) - candidate = pathlib.PurePosixPath(package_path) - if candidate.is_absolute() or ".." in candidate.parts: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" - ) - if not package_path or "node_modules" not in candidate.parts: - continue - - resolved = metadata.get("resolved") - if metadata.get("link") is True: - if not isinstance(resolved, str) or not resolved or "\\" in resolved: - raise ValueError( - f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" - ) - link_target = pathlib.PurePosixPath(resolved) - if ( - link_target.is_absolute() - or ".." in link_target.parts - or "node_modules" in link_target.parts - ): - raise ValueError( - f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" - ) - continue - - identity = _npm_package_identity(candidate) - if identity is None: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has a malformed npm package identity" - ) - - has_resolved = "resolved" in metadata - has_integrity = "integrity" in metadata - if has_resolved != has_integrity: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must not partially declare resolved or integrity" - ) - if has_resolved: - _validate_npm_registry_pin( - lock_path, - package_path, - metadata.get("resolved"), - metadata.get("integrity"), - ) - continue - - version = metadata.get("version") - if not isinstance(version, str) or not version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must declare a nonempty exact version" - ) - canonical_path = f"node_modules/{identity}" - if package_path == canonical_path: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must provide a canonical root pin" - ) - canonical_metadata = packages.get(canonical_path) - if ( - not isinstance(canonical_metadata, dict) - or canonical_metadata.get("link") is True - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" - ) - canonical_version = canonical_metadata.get("version") - if not isinstance(canonical_version, str) or not canonical_version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" - ) - if canonical_version != version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must match the exact canonical version at {canonical_path}" - ) - _validate_npm_registry_pin( - lock_path, - canonical_path, - canonical_metadata.get("resolved"), - canonical_metadata.get("integrity"), - ) -''' - source_path.write_text(source[:loop_start] + new_loop + source[loop_end:], encoding='utf-8') - - doctoring_path = Path('docs/doctoring/npm-nested-metadata-canonical-pins.md') - doctoring_path.parent.mkdir(parents=True, exist_ok=True) - doctoring_path.write_text('''# Canonical pins for metadata-only nested npm locations - -## Decision - -Changed-head npm lock validation continues to accept only lockfile versions 2 and -3, safe repository-relative package locations, safe workspace links, and exact -public-registry SHA-512 artifact pins. One narrowly defined npm serialization is -also accepted: a non-link nested `node_modules` location may omit `resolved` and -`integrity` only when it declares a nonempty exact `version` and the canonical -root location for the same normalized package identity supplies the same version, -one HTTPS `registry.npmjs.org` tarball, and one valid SHA-512 SRI value. - -For `apps/desktop/node_modules/@types/react-dom`, the only eligible canonical -location is `node_modules/@types/react-dom`. Scoped identity is derived from the -two segments after the final `node_modules`; an unscoped identity uses exactly -one segment. Missing, malformed, ambiguous, linked, version-mismatched, partially -pinned, non-registry, or invalid-integrity canonical evidence fails closed. -Complete nested pins remain independently valid and are not rebound to another -version. - -## Trust and interpretation boundary - -The validator consumes the original lock bytes unchanged. It does not repair, -resolve, install, fetch, infer a version range, or synthesize artifact metadata. -The canonical lookup is a structural provenance check for one lock document, not -a claim that arbitrary duplicated locations are interchangeable. Pull-request -code and lifecycle hooks remain outside the trusted materializer. - -npm documents `packages` as a location-keyed map and notes that descriptors may -contain version and classification metadata while artifact fields depend on the -resolved dependency form. npm workspaces are managed from one top-level package -and lock while nested packages are linked into the root installation. This -central policy is intentionally stricter: a metadata-only installed location is -accepted only through one exact root package identity, version, registry origin, -and SHA-512 integrity closure. - -## Verification - -Permanent tests include the BandScope scoped peer shape, an unscoped equivalent, -an independently pinned nested version, missing canonical metadata, version -mismatch, partial pins, hostile registry URLs, invalid SRI, malformed scoped and -unscoped identities, empty versions, and metadata-only root entries. Python 3.10 -compilation and Python 3.14 focused/full tests enforce complete production -statement, branch, and public-docstring coverage. - -## Rollback - -Rollback removes the canonical metadata-only branch and returns to rejecting all -non-link installed locations without local artifact fields. It must not weaken -URL, path, link, lock-version, SHA-512, immutable-source, or offline-execution -controls. - -## References - -npm, Inc. (2026). *package-lock.json*. npm Docs. -https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ - -npm, Inc. (2026). *Workspaces*. npm Docs. -https://docs.npmjs.com/cli/v11/using-npm/workspaces/ -''', encoding='utf-8') - - changelog_path = Path('CHANGELOG.md') - changelog = changelog_path.read_text(encoding='utf-8') - fixed_anchor = '### Fixed\n\n' - entry = ( - '- Accepted metadata-only nested npm v2/v3 package locations only when one ' - 'canonical root package has the same normalized identity and exact version ' - 'plus a validated public-registry tarball and SHA-512 integrity, while ' - 'retaining fail-closed path, link, partial-pin, origin, and SRI controls.\n' - ) - if changelog.count(fixed_anchor) != 1: - raise SystemExit('CHANGELOG Fixed anchor changed') - if entry not in changelog: - changelog = changelog.replace(fixed_anchor, fixed_anchor + entry, 1) - changelog_path.write_text(changelog, encoding='utf-8') - PY - git diff --check - - - name: Run focused and complete quality evidence - run: | - python -m coverage erase - python -m coverage run --branch -m pytest -q \ - tests/test_materialize_base_javascript_packages.py \ - tests/test_npm_nested_metadata_lock_validation.py - python -m coverage report \ - --include=scripts/ci/materialize_base_javascript_packages.py \ - --show-missing \ - --fail-under=100 - python -m interrogate --fail-under 100 scripts/ci/materialize_base_javascript_packages.py - python -m compileall -q \ - scripts/ci/materialize_base_javascript_packages.py \ - tests/test_materialize_base_javascript_packages.py \ - tests/test_npm_nested_metadata_lock_validation.py - python -m coverage erase - python -m coverage run -m pytest tests -q - python -m coverage report --show-missing --fail-under=100 - git diff --check - - - name: Commit permanent non-workflow implementation - env: - EXPECTED_SHA: ${{ github.sha }} - EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation - run: | - remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" - test "$remote_sha" = "$EXPECTED_SHA" - expected="$(printf '%s\n' \ - 'CHANGELOG.md' \ - 'docs/doctoring/npm-nested-metadata-canonical-pins.md' \ - 'scripts/ci/materialize_base_javascript_packages.py' | sort)" - actual="$(git diff --name-only | sort)" - test "$actual" = "$expected" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add CHANGELOG.md \ - docs/doctoring/npm-nested-metadata-canonical-pins.md \ - scripts/ci/materialize_base_javascript_packages.py - git commit -m "fix(coverage): validate nested npm metadata through canonical pins" - test "$(git rev-parse HEAD^)" = "$EXPECTED_SHA" - git push origin "HEAD:refs/heads/$EXPECTED_BRANCH" From c03a634f087a5ac3db4841eeca4393bed24d800b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:13:57 +0900 Subject: [PATCH 15/19] chore(coverage): stage reviewed nested metadata implementation --- scripts/ci/apply_pr807_nested_metadata.py | 278 ++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 scripts/ci/apply_pr807_nested_metadata.py diff --git a/scripts/ci/apply_pr807_nested_metadata.py b/scripts/ci/apply_pr807_nested_metadata.py new file mode 100644 index 000000000..a169c5c00 --- /dev/null +++ b/scripts/ci/apply_pr807_nested_metadata.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python3 +"""Apply the reviewed PR 807 canonical npm metadata implementation once.""" + +from __future__ import annotations + +from pathlib import Path + + +SOURCE_PATH = Path("scripts/ci/materialize_base_javascript_packages.py") +DOCTORING_PATH = Path("docs/doctoring/npm-nested-metadata-canonical-pins.md") +CHANGELOG_PATH = Path("CHANGELOG.md") + + +HELPERS = r''' + +def _npm_package_identity(candidate: pathlib.PurePosixPath) -> str | None: + """Return the exact package identity after the final node_modules segment.""" + + positions = [ + index for index, segment in enumerate(candidate.parts) if segment == "node_modules" + ] + if not positions: + return None + tail = candidate.parts[positions[-1] + 1 :] + if len(tail) == 1 and not tail[0].startswith("@"): + identity = tail[0] + elif len(tail) == 2 and tail[0].startswith("@"): + identity = f"{tail[0]}/{tail[1]}" + else: + return None + return identity if NPM_PACKAGE_IDENTITY_RE.fullmatch(identity) else None + + +def _validate_npm_registry_pin( + lock_path: str, + package_path: str, + resolved: object, + integrity: object, +) -> None: + """Require one exact public npm tarball and SHA-512 integrity pair.""" + + if not isinstance(resolved, str) or not isinstance(integrity, str): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must pin a registry tarball and SHA-512 integrity" + ) + parsed = urllib.parse.urlsplit(resolved) + try: + parsed_port = parsed.port + except ValueError as exc: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has an invalid registry URL" + ) from exc + if ( + parsed.scheme != "https" + or parsed.hostname != NPM_REGISTRY_HOST + or parsed.username is not None + or parsed.password is not None + or parsed_port is not None + or parsed.query + or parsed.fragment + or not parsed.path.startswith("/") + or not parsed.path.endswith(".tgz") + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must resolve from https://{NPM_REGISTRY_HOST}/" + ) + if not SHA512_SRI_RE.fullmatch(integrity): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must use one SHA-512 integrity value" + ) + + +def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: +''' + + +NEW_LOOP = r''' for package_path, metadata in sorted(packages.items()): + if not isinstance(package_path, str) or not isinstance(metadata, dict): + raise ValueError( + f"current-head npm lock {lock_path} contains malformed package metadata" + ) + if "\\" in package_path: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" + ) + candidate = pathlib.PurePosixPath(package_path) + if candidate.is_absolute() or ".." in candidate.parts: + raise ValueError( + f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" + ) + if not package_path or "node_modules" not in candidate.parts: + continue + + resolved = metadata.get("resolved") + if metadata.get("link") is True: + if not isinstance(resolved, str) or not resolved or "\\" in resolved: + raise ValueError( + f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" + ) + link_target = pathlib.PurePosixPath(resolved) + if ( + link_target.is_absolute() + or ".." in link_target.parts + or "node_modules" in link_target.parts + ): + raise ValueError( + f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" + ) + continue + + identity = _npm_package_identity(candidate) + if identity is None: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has a malformed npm package identity" + ) + + has_resolved = "resolved" in metadata + has_integrity = "integrity" in metadata + if has_resolved != has_integrity: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must not partially declare resolved or integrity" + ) + if has_resolved: + _validate_npm_registry_pin( + lock_path, + package_path, + metadata.get("resolved"), + metadata.get("integrity"), + ) + continue + + version = metadata.get("version") + if not isinstance(version, str) or not version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must declare a nonempty exact version" + ) + canonical_path = f"node_modules/{identity}" + if package_path == canonical_path: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must provide a canonical root pin" + ) + canonical_metadata = packages.get(canonical_path) + if ( + not isinstance(canonical_metadata, dict) + or canonical_metadata.get("link") is True + ): + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" + ) + canonical_version = canonical_metadata.get("version") + if not isinstance(canonical_version, str) or not canonical_version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" + ) + if canonical_version != version: + raise ValueError( + f"current-head npm lock {lock_path} package {package_path} must match the exact canonical version at {canonical_path}" + ) + _validate_npm_registry_pin( + lock_path, + canonical_path, + canonical_metadata.get("resolved"), + canonical_metadata.get("integrity"), + ) +''' + + +DOCTORING = """# Canonical pins for metadata-only nested npm locations + +## Decision + +Changed-head npm lock validation continues to accept only lockfile versions 2 and +3, safe repository-relative package locations, safe workspace links, and exact +public-registry SHA-512 artifact pins. One narrowly defined npm serialization is +also accepted: a non-link nested `node_modules` location may omit `resolved` and +`integrity` only when it declares a nonempty exact `version` and the canonical +root location for the same normalized package identity supplies the same version, +one HTTPS `registry.npmjs.org` tarball, and one valid SHA-512 SRI value. + +For `apps/desktop/node_modules/@types/react-dom`, the only eligible canonical +location is `node_modules/@types/react-dom`. Scoped identity is derived from the +two segments after the final `node_modules`; an unscoped identity uses exactly +one segment. Missing, malformed, linked, version-mismatched, partially pinned, +non-registry, or invalid-integrity canonical evidence fails closed. Complete +nested pins remain independently valid and are not rebound to another version. + +## Trust and interpretation boundary + +The validator consumes the original lock bytes unchanged. It does not repair, +resolve, install, fetch, infer a version range, or synthesize artifact metadata. +The canonical lookup is a structural provenance check for one lock document, not +a claim that arbitrary duplicated locations are interchangeable. Pull-request +code and lifecycle hooks remain outside the trusted materializer. + +npm documents `packages` as a location-keyed map and notes that descriptors may +contain version and classification metadata while artifact fields depend on the +resolved dependency form. npm workspaces are managed from one top-level package +and lock while nested packages are linked into the root installation. This +central policy is intentionally stricter: a metadata-only installed location is +accepted only through one exact root package identity, version, registry origin, +and SHA-512 integrity closure. + +## Verification + +Permanent tests include the BandScope scoped peer shape, an unscoped equivalent, +an independently pinned nested version, missing canonical metadata, version +mismatch, partial pins, hostile registry URLs, invalid SRI, malformed scoped and +unscoped identities, empty versions, and metadata-only root entries. Python 3.10 +compilation and Python 3.14 focused/full tests enforce complete production +statement, branch, and public-docstring coverage. + +## Rollback + +Rollback removes the canonical metadata-only branch and returns to rejecting all +non-link installed locations without local artifact fields. It must not weaken +URL, path, link, lock-version, SHA-512, immutable-source, or offline-execution +controls. + +## References + +npm, Inc. (2026). *package-lock.json*. npm Docs. +https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ + +npm, Inc. (2026). *Workspaces*. npm Docs. +https://docs.npmjs.com/cli/v11/using-npm/workspaces/ +""" + + +def main() -> None: + """Apply the bounded implementation, doctoring, and changelog edits.""" + + source = SOURCE_PATH.read_text(encoding="utf-8") + constant_anchor = 'SHA512_SRI_RE = re.compile(r"^sha512-[A-Za-z0-9+/]{86}==$")\n' + constant_replacement = constant_anchor + ( + "NPM_PACKAGE_IDENTITY_RE = re.compile(\n" + ' r"^(?:@[a-z0-9][a-z0-9._~-]*/)?[a-z0-9][a-z0-9._~-]*$"\n' + ")\n" + ) + if source.count(constant_anchor) != 1: + raise SystemExit("npm identity constant anchor changed") + source = source.replace(constant_anchor, constant_replacement, 1) + + function_anchor = ( + "\ndef validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None:\n" + ) + if source.count(function_anchor) != 1: + raise SystemExit("validator function anchor changed") + source = source.replace(function_anchor, HELPERS, 1) + + loop_start = source.index( + " for package_path, metadata in sorted(packages.items()):\n" + ) + loop_end = source.index("\n\ndef materialize(\n", loop_start) + SOURCE_PATH.write_text( + source[:loop_start] + NEW_LOOP + source[loop_end:], + encoding="utf-8", + ) + + DOCTORING_PATH.parent.mkdir(parents=True, exist_ok=True) + DOCTORING_PATH.write_text(DOCTORING, encoding="utf-8") + + changelog = CHANGELOG_PATH.read_text(encoding="utf-8") + fixed_anchor = "### Fixed\n\n" + entry = ( + "- Accepted metadata-only nested npm v2/v3 package locations only when one " + "canonical root package has the same normalized identity and exact version " + "plus a validated public-registry tarball and SHA-512 integrity, while " + "retaining fail-closed path, link, partial-pin, origin, and SRI controls.\n" + ) + if changelog.count(fixed_anchor) != 1: + raise SystemExit("CHANGELOG Fixed anchor changed") + if entry not in changelog: + changelog = changelog.replace(fixed_anchor, fixed_anchor + entry, 1) + CHANGELOG_PATH.write_text(changelog, encoding="utf-8") + + +if __name__ == "__main__": + main() From 8873048809ccf166a5c150af76d92b7d909bc83c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:15:31 +0900 Subject: [PATCH 16/19] chore(coverage): apply reviewed nested metadata implementation --- .../pr807-apply-nested-metadata-once.yml | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 .github/workflows/pr807-apply-nested-metadata-once.yml diff --git a/.github/workflows/pr807-apply-nested-metadata-once.yml b/.github/workflows/pr807-apply-nested-metadata-once.yml new file mode 100644 index 000000000..8ba79814e --- /dev/null +++ b/.github/workflows/pr807-apply-nested-metadata-once.yml @@ -0,0 +1,105 @@ +name: PR 807 Apply Nested npm Metadata Once + +on: + push: + branches: + - fix/npm-nested-metadata-lock-validation + paths: + - .github/workflows/pr807-apply-nested-metadata-once.yml + +permissions: + contents: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + apply: + if: >- + github.repository == 'ContextualWisdomLab/.github' && + github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' + runs-on: ubuntu-24.04 + timeout-minutes: 35 + steps: + - name: Harden runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + + - name: Checkout exact trigger head + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + ref: ${{ github.sha }} + fetch-depth: 2 + persist-credentials: true + + - name: Refuse concurrent branch movement + env: + EXPECTED_SHA: ${{ github.sha }} + EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" + remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" + test "$remote_sha" = "$EXPECTED_SHA" + + - name: Set up Python 3.14 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: requirements-opencode-review-ci-hashes.txt + + - name: Install exact hash-locked quality tooling + run: >- + python -m pip install --disable-pip-version-check --require-hashes + -r requirements-opencode-review-ci-hashes.txt + + - name: Apply reviewed implementation + run: | + python scripts/ci/apply_pr807_nested_metadata.py + rm -- scripts/ci/apply_pr807_nested_metadata.py + git diff --check + + - name: Verify focused and complete quality evidence + run: | + python -m coverage erase + python -m coverage run --branch -m pytest -q \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + python -m coverage report \ + --include=scripts/ci/materialize_base_javascript_packages.py \ + --show-missing \ + --fail-under=100 + python -m interrogate --fail-under 100 scripts/ci/materialize_base_javascript_packages.py + python -m compileall -q \ + scripts/ci/materialize_base_javascript_packages.py \ + tests/test_materialize_base_javascript_packages.py \ + tests/test_npm_nested_metadata_lock_validation.py + python -m coverage erase + python -m coverage run -m pytest tests -q + python -m coverage report --show-missing --fail-under=100 + git diff --check + + - name: Commit permanent non-workflow implementation + env: + EXPECTED_SHA: ${{ github.sha }} + EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + run: | + remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" + test "$remote_sha" = "$EXPECTED_SHA" + expected="$(printf '%s\n' \ + 'CHANGELOG.md' \ + 'docs/doctoring/npm-nested-metadata-canonical-pins.md' \ + 'scripts/ci/apply_pr807_nested_metadata.py' \ + 'scripts/ci/materialize_base_javascript_packages.py' | sort)" + actual="$(git diff --name-only | sort)" + test "$actual" = "$expected" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A CHANGELOG.md \ + docs/doctoring/npm-nested-metadata-canonical-pins.md \ + scripts/ci/apply_pr807_nested_metadata.py \ + scripts/ci/materialize_base_javascript_packages.py + git commit -m "fix(coverage): validate nested npm metadata through canonical pins" + test "$(git rev-parse HEAD^)" = "$EXPECTED_SHA" + git push origin "HEAD:refs/heads/$EXPECTED_BRANCH" From 3e0eafa4237f9ef07aa71f2804b3fd674c152bfb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:37:12 +0900 Subject: [PATCH 17/19] ci(coverage): run bounded nested-metadata finalizer --- .../pr807-apply-nested-metadata-once.yml | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr807-apply-nested-metadata-once.yml b/.github/workflows/pr807-apply-nested-metadata-once.yml index 8ba79814e..b9b004180 100644 --- a/.github/workflows/pr807-apply-nested-metadata-once.yml +++ b/.github/workflows/pr807-apply-nested-metadata-once.yml @@ -6,18 +6,25 @@ on: - fix/npm-nested-metadata-lock-validation paths: - .github/workflows/pr807-apply-nested-metadata-once.yml + - scripts/ci/apply_pr807_nested_metadata.py permissions: - contents: write + contents: read env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true +concurrency: + group: pr807-nested-metadata-finalizer-${{ github.ref }} + cancel-in-progress: false + jobs: apply: if: >- github.repository == 'ContextualWisdomLab/.github' && github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' + permissions: + contents: write runs-on: ubuntu-24.04 timeout-minutes: 35 steps: @@ -26,17 +33,18 @@ jobs: with: egress-policy: audit - - name: Checkout exact trigger head + - name: Checkout exact trigger head without persisted credentials uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ github.sha }} fetch-depth: 2 - persist-credentials: true + persist-credentials: false - name: Refuse concurrent branch movement env: EXPECTED_SHA: ${{ github.sha }} EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + shell: bash --noprofile --norc -e -o pipefail {0} run: | test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" @@ -50,17 +58,21 @@ jobs: cache-dependency-path: requirements-opencode-review-ci-hashes.txt - name: Install exact hash-locked quality tooling + shell: bash --noprofile --norc -e -o pipefail {0} run: >- python -m pip install --disable-pip-version-check --require-hashes -r requirements-opencode-review-ci-hashes.txt - - name: Apply reviewed implementation + - name: Apply reviewed permanent implementation and remove temporary machinery + shell: bash --noprofile --norc -e -o pipefail {0} run: | python scripts/ci/apply_pr807_nested_metadata.py rm -- scripts/ci/apply_pr807_nested_metadata.py + rm -- .github/workflows/pr807-apply-nested-metadata-once.yml git diff --check - name: Verify focused and complete quality evidence + shell: bash --noprofile --norc -e -o pipefail {0} run: | python -m coverage erase python -m coverage run --branch -m pytest -q \ @@ -70,7 +82,8 @@ jobs: --include=scripts/ci/materialize_base_javascript_packages.py \ --show-missing \ --fail-under=100 - python -m interrogate --fail-under 100 scripts/ci/materialize_base_javascript_packages.py + python -m interrogate --fail-under 100 \ + scripts/ci/materialize_base_javascript_packages.py python -m compileall -q \ scripts/ci/materialize_base_javascript_packages.py \ tests/test_materialize_base_javascript_packages.py \ @@ -80,14 +93,17 @@ jobs: python -m coverage report --show-missing --fail-under=100 git diff --check - - name: Commit permanent non-workflow implementation + - name: Publish workflow-free permanent commit env: EXPECTED_SHA: ${{ github.sha }} EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation + GH_TOKEN: ${{ github.token }} + shell: bash --noprofile --norc -e -o pipefail {0} run: | remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" test "$remote_sha" = "$EXPECTED_SHA" expected="$(printf '%s\n' \ + '.github/workflows/pr807-apply-nested-metadata-once.yml' \ 'CHANGELOG.md' \ 'docs/doctoring/npm-nested-metadata-canonical-pins.md' \ 'scripts/ci/apply_pr807_nested_metadata.py' \ @@ -96,10 +112,12 @@ jobs: test "$actual" = "$expected" git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A CHANGELOG.md \ - docs/doctoring/npm-nested-metadata-canonical-pins.md \ - scripts/ci/apply_pr807_nested_metadata.py \ - scripts/ci/materialize_base_javascript_packages.py + git add -A + git diff --cached --check git commit -m "fix(coverage): validate nested npm metadata through canonical pins" test "$(git rev-parse HEAD^)" = "$EXPECTED_SHA" - git push origin "HEAD:refs/heads/$EXPECTED_BRANCH" + auth_header="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')" + echo "::add-mask::$auth_header" + git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" \ + push --force-with-lease="refs/heads/${EXPECTED_BRANCH}:${EXPECTED_SHA}" \ + origin "HEAD:refs/heads/${EXPECTED_BRANCH}" From 9c542f63d324b7a41cda0101a6bb88c9849e07ff Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:44:26 +0900 Subject: [PATCH 18/19] chore(coverage): remove PR-controlled npm metadata writer --- .../pr807-apply-nested-metadata-once.yml | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 .github/workflows/pr807-apply-nested-metadata-once.yml diff --git a/.github/workflows/pr807-apply-nested-metadata-once.yml b/.github/workflows/pr807-apply-nested-metadata-once.yml deleted file mode 100644 index b9b004180..000000000 --- a/.github/workflows/pr807-apply-nested-metadata-once.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: PR 807 Apply Nested npm Metadata Once - -on: - push: - branches: - - fix/npm-nested-metadata-lock-validation - paths: - - .github/workflows/pr807-apply-nested-metadata-once.yml - - scripts/ci/apply_pr807_nested_metadata.py - -permissions: - contents: read - -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -concurrency: - group: pr807-nested-metadata-finalizer-${{ github.ref }} - cancel-in-progress: false - -jobs: - apply: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == 'refs/heads/fix/npm-nested-metadata-lock-validation' - permissions: - contents: write - runs-on: ubuntu-24.04 - timeout-minutes: 35 - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 - with: - egress-policy: audit - - - name: Checkout exact trigger head without persisted credentials - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - fetch-depth: 2 - persist-credentials: false - - - name: Refuse concurrent branch movement - env: - EXPECTED_SHA: ${{ github.sha }} - EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" - remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" - test "$remote_sha" = "$EXPECTED_SHA" - - - name: Set up Python 3.14 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - cache: pip - cache-dependency-path: requirements-opencode-review-ci-hashes.txt - - - name: Install exact hash-locked quality tooling - shell: bash --noprofile --norc -e -o pipefail {0} - run: >- - python -m pip install --disable-pip-version-check --require-hashes - -r requirements-opencode-review-ci-hashes.txt - - - name: Apply reviewed permanent implementation and remove temporary machinery - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python scripts/ci/apply_pr807_nested_metadata.py - rm -- scripts/ci/apply_pr807_nested_metadata.py - rm -- .github/workflows/pr807-apply-nested-metadata-once.yml - git diff --check - - - name: Verify focused and complete quality evidence - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - python -m coverage erase - python -m coverage run --branch -m pytest -q \ - tests/test_materialize_base_javascript_packages.py \ - tests/test_npm_nested_metadata_lock_validation.py - python -m coverage report \ - --include=scripts/ci/materialize_base_javascript_packages.py \ - --show-missing \ - --fail-under=100 - python -m interrogate --fail-under 100 \ - scripts/ci/materialize_base_javascript_packages.py - python -m compileall -q \ - scripts/ci/materialize_base_javascript_packages.py \ - tests/test_materialize_base_javascript_packages.py \ - tests/test_npm_nested_metadata_lock_validation.py - python -m coverage erase - python -m coverage run -m pytest tests -q - python -m coverage report --show-missing --fail-under=100 - git diff --check - - - name: Publish workflow-free permanent commit - env: - EXPECTED_SHA: ${{ github.sha }} - EXPECTED_BRANCH: fix/npm-nested-metadata-lock-validation - GH_TOKEN: ${{ github.token }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - remote_sha="$(git ls-remote origin "refs/heads/$EXPECTED_BRANCH" | awk '{print $1}')" - test "$remote_sha" = "$EXPECTED_SHA" - expected="$(printf '%s\n' \ - '.github/workflows/pr807-apply-nested-metadata-once.yml' \ - 'CHANGELOG.md' \ - 'docs/doctoring/npm-nested-metadata-canonical-pins.md' \ - 'scripts/ci/apply_pr807_nested_metadata.py' \ - 'scripts/ci/materialize_base_javascript_packages.py' | sort)" - actual="$(git diff --name-only | sort)" - test "$actual" = "$expected" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git commit -m "fix(coverage): validate nested npm metadata through canonical pins" - test "$(git rev-parse HEAD^)" = "$EXPECTED_SHA" - auth_header="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')" - echo "::add-mask::$auth_header" - git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" \ - push --force-with-lease="refs/heads/${EXPECTED_BRANCH}:${EXPECTED_SHA}" \ - origin "HEAD:refs/heads/${EXPECTED_BRANCH}" From 0ce11b73992851afe991a5e86991db398c9d9900 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 7 Aug 2026 10:44:44 +0900 Subject: [PATCH 19/19] chore(coverage): remove PR-controlled npm metadata patcher --- scripts/ci/apply_pr807_nested_metadata.py | 278 ---------------------- 1 file changed, 278 deletions(-) delete mode 100644 scripts/ci/apply_pr807_nested_metadata.py diff --git a/scripts/ci/apply_pr807_nested_metadata.py b/scripts/ci/apply_pr807_nested_metadata.py deleted file mode 100644 index a169c5c00..000000000 --- a/scripts/ci/apply_pr807_nested_metadata.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python3 -"""Apply the reviewed PR 807 canonical npm metadata implementation once.""" - -from __future__ import annotations - -from pathlib import Path - - -SOURCE_PATH = Path("scripts/ci/materialize_base_javascript_packages.py") -DOCTORING_PATH = Path("docs/doctoring/npm-nested-metadata-canonical-pins.md") -CHANGELOG_PATH = Path("CHANGELOG.md") - - -HELPERS = r''' - -def _npm_package_identity(candidate: pathlib.PurePosixPath) -> str | None: - """Return the exact package identity after the final node_modules segment.""" - - positions = [ - index for index, segment in enumerate(candidate.parts) if segment == "node_modules" - ] - if not positions: - return None - tail = candidate.parts[positions[-1] + 1 :] - if len(tail) == 1 and not tail[0].startswith("@"): - identity = tail[0] - elif len(tail) == 2 and tail[0].startswith("@"): - identity = f"{tail[0]}/{tail[1]}" - else: - return None - return identity if NPM_PACKAGE_IDENTITY_RE.fullmatch(identity) else None - - -def _validate_npm_registry_pin( - lock_path: str, - package_path: str, - resolved: object, - integrity: object, -) -> None: - """Require one exact public npm tarball and SHA-512 integrity pair.""" - - if not isinstance(resolved, str) or not isinstance(integrity, str): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must pin a registry tarball and SHA-512 integrity" - ) - parsed = urllib.parse.urlsplit(resolved) - try: - parsed_port = parsed.port - except ValueError as exc: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has an invalid registry URL" - ) from exc - if ( - parsed.scheme != "https" - or parsed.hostname != NPM_REGISTRY_HOST - or parsed.username is not None - or parsed.password is not None - or parsed_port is not None - or parsed.query - or parsed.fragment - or not parsed.path.startswith("/") - or not parsed.path.endswith(".tgz") - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must resolve from https://{NPM_REGISTRY_HOST}/" - ) - if not SHA512_SRI_RE.fullmatch(integrity): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must use one SHA-512 integrity value" - ) - - -def validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None: -''' - - -NEW_LOOP = r''' for package_path, metadata in sorted(packages.items()): - if not isinstance(package_path, str) or not isinstance(metadata, dict): - raise ValueError( - f"current-head npm lock {lock_path} contains malformed package metadata" - ) - if "\\" in package_path: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" - ) - candidate = pathlib.PurePosixPath(package_path) - if candidate.is_absolute() or ".." in candidate.parts: - raise ValueError( - f"current-head npm lock {lock_path} contains unsafe package path {package_path!r}" - ) - if not package_path or "node_modules" not in candidate.parts: - continue - - resolved = metadata.get("resolved") - if metadata.get("link") is True: - if not isinstance(resolved, str) or not resolved or "\\" in resolved: - raise ValueError( - f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" - ) - link_target = pathlib.PurePosixPath(resolved) - if ( - link_target.is_absolute() - or ".." in link_target.parts - or "node_modules" in link_target.parts - ): - raise ValueError( - f"current-head npm lock {lock_path} contains an unsafe workspace link for {package_path}" - ) - continue - - identity = _npm_package_identity(candidate) - if identity is None: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has a malformed npm package identity" - ) - - has_resolved = "resolved" in metadata - has_integrity = "integrity" in metadata - if has_resolved != has_integrity: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must not partially declare resolved or integrity" - ) - if has_resolved: - _validate_npm_registry_pin( - lock_path, - package_path, - metadata.get("resolved"), - metadata.get("integrity"), - ) - continue - - version = metadata.get("version") - if not isinstance(version, str) or not version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must declare a nonempty exact version" - ) - canonical_path = f"node_modules/{identity}" - if package_path == canonical_path: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must provide a canonical root pin" - ) - canonical_metadata = packages.get(canonical_path) - if ( - not isinstance(canonical_metadata, dict) - or canonical_metadata.get("link") is True - ): - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" - ) - canonical_version = canonical_metadata.get("version") - if not isinstance(canonical_version, str) or not canonical_version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} has no canonical root pin at {canonical_path}" - ) - if canonical_version != version: - raise ValueError( - f"current-head npm lock {lock_path} package {package_path} must match the exact canonical version at {canonical_path}" - ) - _validate_npm_registry_pin( - lock_path, - canonical_path, - canonical_metadata.get("resolved"), - canonical_metadata.get("integrity"), - ) -''' - - -DOCTORING = """# Canonical pins for metadata-only nested npm locations - -## Decision - -Changed-head npm lock validation continues to accept only lockfile versions 2 and -3, safe repository-relative package locations, safe workspace links, and exact -public-registry SHA-512 artifact pins. One narrowly defined npm serialization is -also accepted: a non-link nested `node_modules` location may omit `resolved` and -`integrity` only when it declares a nonempty exact `version` and the canonical -root location for the same normalized package identity supplies the same version, -one HTTPS `registry.npmjs.org` tarball, and one valid SHA-512 SRI value. - -For `apps/desktop/node_modules/@types/react-dom`, the only eligible canonical -location is `node_modules/@types/react-dom`. Scoped identity is derived from the -two segments after the final `node_modules`; an unscoped identity uses exactly -one segment. Missing, malformed, linked, version-mismatched, partially pinned, -non-registry, or invalid-integrity canonical evidence fails closed. Complete -nested pins remain independently valid and are not rebound to another version. - -## Trust and interpretation boundary - -The validator consumes the original lock bytes unchanged. It does not repair, -resolve, install, fetch, infer a version range, or synthesize artifact metadata. -The canonical lookup is a structural provenance check for one lock document, not -a claim that arbitrary duplicated locations are interchangeable. Pull-request -code and lifecycle hooks remain outside the trusted materializer. - -npm documents `packages` as a location-keyed map and notes that descriptors may -contain version and classification metadata while artifact fields depend on the -resolved dependency form. npm workspaces are managed from one top-level package -and lock while nested packages are linked into the root installation. This -central policy is intentionally stricter: a metadata-only installed location is -accepted only through one exact root package identity, version, registry origin, -and SHA-512 integrity closure. - -## Verification - -Permanent tests include the BandScope scoped peer shape, an unscoped equivalent, -an independently pinned nested version, missing canonical metadata, version -mismatch, partial pins, hostile registry URLs, invalid SRI, malformed scoped and -unscoped identities, empty versions, and metadata-only root entries. Python 3.10 -compilation and Python 3.14 focused/full tests enforce complete production -statement, branch, and public-docstring coverage. - -## Rollback - -Rollback removes the canonical metadata-only branch and returns to rejecting all -non-link installed locations without local artifact fields. It must not weaken -URL, path, link, lock-version, SHA-512, immutable-source, or offline-execution -controls. - -## References - -npm, Inc. (2026). *package-lock.json*. npm Docs. -https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/ - -npm, Inc. (2026). *Workspaces*. npm Docs. -https://docs.npmjs.com/cli/v11/using-npm/workspaces/ -""" - - -def main() -> None: - """Apply the bounded implementation, doctoring, and changelog edits.""" - - source = SOURCE_PATH.read_text(encoding="utf-8") - constant_anchor = 'SHA512_SRI_RE = re.compile(r"^sha512-[A-Za-z0-9+/]{86}==$")\n' - constant_replacement = constant_anchor + ( - "NPM_PACKAGE_IDENTITY_RE = re.compile(\n" - ' r"^(?:@[a-z0-9][a-z0-9._~-]*/)?[a-z0-9][a-z0-9._~-]*$"\n' - ")\n" - ) - if source.count(constant_anchor) != 1: - raise SystemExit("npm identity constant anchor changed") - source = source.replace(constant_anchor, constant_replacement, 1) - - function_anchor = ( - "\ndef validate_head_npm_lock(lock_path: str, lock_content: bytes) -> None:\n" - ) - if source.count(function_anchor) != 1: - raise SystemExit("validator function anchor changed") - source = source.replace(function_anchor, HELPERS, 1) - - loop_start = source.index( - " for package_path, metadata in sorted(packages.items()):\n" - ) - loop_end = source.index("\n\ndef materialize(\n", loop_start) - SOURCE_PATH.write_text( - source[:loop_start] + NEW_LOOP + source[loop_end:], - encoding="utf-8", - ) - - DOCTORING_PATH.parent.mkdir(parents=True, exist_ok=True) - DOCTORING_PATH.write_text(DOCTORING, encoding="utf-8") - - changelog = CHANGELOG_PATH.read_text(encoding="utf-8") - fixed_anchor = "### Fixed\n\n" - entry = ( - "- Accepted metadata-only nested npm v2/v3 package locations only when one " - "canonical root package has the same normalized identity and exact version " - "plus a validated public-registry tarball and SHA-512 integrity, while " - "retaining fail-closed path, link, partial-pin, origin, and SRI controls.\n" - ) - if changelog.count(fixed_anchor) != 1: - raise SystemExit("CHANGELOG Fixed anchor changed") - if entry not in changelog: - changelog = changelog.replace(fixed_anchor, fixed_anchor + entry, 1) - CHANGELOG_PATH.write_text(changelog, encoding="utf-8") - - -if __name__ == "__main__": - main()