Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
cf014e8
test(coverage): specify nested npm metadata lock validation
seonghobae Aug 6, 2026
6032fa9
ci: add nested npm materializer trigger
seonghobae Aug 6, 2026
4b2fcee
ci: trigger nested npm metadata materializer
seonghobae Aug 6, 2026
202a91e
ci: add PR 807 materializer blank-line repair
seonghobae Aug 7, 2026
de6e8b0
ci: trigger PR 807 materializer repair
seonghobae Aug 7, 2026
3136fc7
chore(coverage): remove npm metadata materializer trigger
seonghobae Aug 7, 2026
f1439a7
chore(coverage): remove PR 807 repair trigger
seonghobae Aug 7, 2026
7a3221e
chore(coverage): remove npm metadata materializer workflow
seonghobae Aug 7, 2026
cb1024b
chore(coverage): remove PR 807 repair workflow
seonghobae Aug 7, 2026
f428ccc
chore(coverage): remove npm metadata trigger workflow
seonghobae Aug 7, 2026
9c298d7
test(coverage): define canonical-pin contract for nested npm metadata
seonghobae Aug 7, 2026
ae9d029
ci(coverage): add permanent nested npm metadata quality gate
seonghobae Aug 7, 2026
e1e0751
chore(coverage): implement nested npm metadata pins once
seonghobae Aug 7, 2026
b6efc22
chore(coverage): remove PR 807 implementation writer
seonghobae Aug 7, 2026
c03a634
chore(coverage): stage reviewed nested metadata implementation
seonghobae Aug 7, 2026
8873048
chore(coverage): apply reviewed nested metadata implementation
seonghobae Aug 7, 2026
3e0eafa
ci(coverage): run bounded nested-metadata finalizer
seonghobae Aug 7, 2026
9c542f6
chore(coverage): remove PR-controlled npm metadata writer
seonghobae Aug 7, 2026
0ce11b7
chore(coverage): remove PR-controlled npm metadata patcher
seonghobae Aug 7, 2026
94ab4f8
fix(coverage): resolve nested npm metadata through canonical pins
seonghobae Aug 7, 2026
65bfbc5
docs(coverage): define canonical npm metadata pin inheritance
seonghobae Aug 7, 2026
0c74964
chore(changelog): record canonical npm metadata pin validation
seonghobae Aug 7, 2026
675994f
fix(coverage): preserve legacy npm diagnostics before version gate
seonghobae Aug 7, 2026
62ee8d9
test(coverage): complete npm validator branch evidence
seonghobae Aug 7, 2026
d4303cc
Merge branch 'main' into fix/npm-nested-metadata-lock-validation
opencode-agent[bot] Aug 7, 2026
1dee3d2
docs(coverage): align npm explicit-port policy
seonghobae Aug 7, 2026
8185f10
test(security): reject symlinked materialization parents
seonghobae Aug 7, 2026
e2d9bbd
fix(security): reject symlinked materialization paths
seonghobae Aug 7, 2026
df190e3
fix(security): preserve symlink rejection contract
seonghobae Aug 7, 2026
8579d21
test(coverage): exercise non-directory output component rejection
seonghobae Aug 7, 2026
342c6bc
chore(npm): stage descriptor-safe output part 00
seonghobae Aug 7, 2026
ed07a11
chore(npm): stage descriptor-safe output part 01
seonghobae Aug 7, 2026
f06176e
chore(npm): stage descriptor-safe output part 02
seonghobae Aug 7, 2026
770f2d3
chore(npm): stage descriptor-safe output part 03
seonghobae Aug 7, 2026
a5a61c3
chore(npm): stage descriptor-safe output part 04
seonghobae Aug 7, 2026
7b1a08f
chore(stack): reconcile npm metadata validation with main
seonghobae Aug 7, 2026
e2fc933
test(coverage): reproduce JavaScript materializer output races
seonghobae Aug 7, 2026
c3f8f3e
test(coverage): run JavaScript output-race regressions
seonghobae Aug 7, 2026
e17af4c
fix(coverage): pin JavaScript materializer output descriptors
seonghobae Aug 7, 2026
245fe2f
test(coverage): close JavaScript materializer security branches
seonghobae Aug 7, 2026
96c2043
test(security): prove descriptor ancestry and cleanup races
seonghobae Aug 7, 2026
0d7b3e6
ci(security): execute descriptor ancestry regressions
seonghobae Aug 7, 2026
e584fba
fix(coverage): harden JavaScript materializer descriptor ancestry
seonghobae Aug 7, 2026
fbd26a4
test(coverage): preserve dir-fd capability under race instrumentation
seonghobae Aug 7, 2026
b736d83
test(coverage): preserve bounded descriptor-open failure
seonghobae Aug 7, 2026
802e90d
test(coverage): cover descriptor cleanup edge branches
seonghobae Aug 7, 2026
07fd3da
test(coverage): execute descriptor edge regressions
seonghobae Aug 7, 2026
6bbc93a
test(security): prove ancestor creation and complete rollback
seonghobae Aug 7, 2026
f851385
test(coverage): exercise existing relative directory
seonghobae Aug 7, 2026
56c368b
test(coverage): execute existing-directory regression
seonghobae Aug 7, 2026
f60beed
test(security): remove capability-masking fixture
seonghobae Aug 7, 2026
f3ef0af
fix(security): separate dir-fd capability identity from instrumentation
seonghobae Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions .github/workflows/npm-nested-metadata-validation-quality-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
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/conftest.py"
- "tests/test_javascript_materializer_descriptor_ancestry.py"
- "tests/test_javascript_materializer_existing_directory_coverage.py"
- "tests/test_javascript_materializer_output_edge_coverage.py"
- "tests/test_javascript_materializer_output_security.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/conftest.py"
- "tests/test_javascript_materializer_descriptor_ancestry.py"
- "tests/test_javascript_materializer_existing_directory_coverage.py"
- "tests/test_javascript_materializer_output_edge_coverage.py"
- "tests/test_javascript_materializer_output_security.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/conftest.py \
tests/test_javascript_materializer_descriptor_ancestry.py \
tests/test_javascript_materializer_existing_directory_coverage.py \
tests/test_javascript_materializer_output_edge_coverage.py \
tests/test_javascript_materializer_output_security.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_javascript_materializer_descriptor_ancestry.py \
tests/test_javascript_materializer_existing_directory_coverage.py \
tests/test_javascript_materializer_output_edge_coverage.py \
tests/test_javascript_materializer_output_security.py \
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/conftest.py \
tests/test_javascript_materializer_descriptor_ancestry.py \
tests/test_javascript_materializer_existing_directory_coverage.py \
tests/test_javascript_materializer_output_edge_coverage.py \
tests/test_javascript_materializer_output_security.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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Accepted npm v2/v3 metadata-only nested workspace and peer locations only when one exact scoped or unscoped canonical root package carries the same version, HTTPS npm-registry tarball, and canonical SHA-512 integrity, while continuing to reject malformed identities, partial pins, metadata-only roots, alternate origins, and version drift.
- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.
- Bound both trusted-uv quality jobs to `github.event.pull_request.head.sha` and added a permanent two-checkout regression contract so exact-head compatibility, coverage, docstring, and compilation claims cannot silently measure GitHub's generated pull-request merge revision.
- Made Strix treat only a single LiteLLM provider-error line containing NVIDIA NIM context and model-catalog 404 evidence as cross-model fallback evidence, rejecting cross-line signal assembly and provider-like target source literals; moved the public default to Nemotron 3 Super 120B and added a second NVIDIA hosted candidate before GitHub Models without neutralizing reported vulnerabilities.
74 changes: 74 additions & 0 deletions docs/doctoring/npm-nested-metadata-canonical-pins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# npm nested metadata canonical pins

## Decision

Changed npm lockfiles remain untrusted pull-request inputs. The central JavaScript dependency materializer accepts npm lockfile versions 2 and 3 only after validating the complete `packages` map. Every non-link package location under a `node_modules` segment must declare a nonempty exact `version`.

npm can serialize a nested workspace or peer location with version and classification metadata while the canonical root location carries the registry tarball and integrity fields. The validator therefore distinguishes two safe forms:

1. **Complete pin** — the location declares both `resolved` and `integrity`. The URL must be an HTTPS tarball on `registry.npmjs.org` with no user information, explicit port, query, or fragment, and the integrity value must be one canonical SHA-512 SRI value.
2. **Metadata-only nested location** — the location declares neither field. It is accepted only when `node_modules/<package identity>` contains one complete pin for the same scoped or unscoped package identity and the exact same version.

A metadata-only canonical root entry is forbidden. A nested location that declares only one of `resolved` or `integrity` is also forbidden. Independently complete nested pins remain valid and may carry a different version because their bytes and integrity are self-contained.

## Package identity

Identity is derived from the path segments after the final `node_modules` component:

- unscoped: exactly one segment, such as `react`;
- scoped: exactly two segments, such as `@types/react-dom`.

Incomplete scopes, additional identity segments, absolute paths, backslashes, and parent traversal fail closed. Workspace links retain their separate bounded relative-link validation and never inherit registry metadata.

```mermaid
flowchart TD
A[npm packages map entry] --> B{link is true?}
B -->|yes| C[Validate bounded relative workspace target]
B -->|no| D[Derive exact package identity and require version]
D --> E{resolved and integrity}
E -->|both present| F[Validate exact npm registry tarball and SHA-512 SRI]
E -->|one present| G[Reject partial pin]
E -->|both absent| H{canonical root?}
H -->|yes| I[Reject metadata-only root]
H -->|no| J[Require same identity and version at complete root pin]
```

## Security and compatibility boundary

The policy does not repair, synthesize, or mutate lockfile metadata. It consumes the validated lock unchanged. It preserves the existing lockfile version, path, link, URL, origin, tarball suffix, and SHA-512 controls while admitting npm's location-keyed metadata representation.

The canonical root pin is a provenance anchor for metadata-only locations, not a claim that all nested locations share one physical installation. A complete nested record is validated independently and does not depend on the root. Missing roots, version drift, malformed identity, partial fields, alternate registries, malformed URLs, and invalid integrity remain blocking.

## Verification

The permanent regression suite includes:

- the BandScope `apps/desktop/node_modules/@types/react-dom` peer-location shape;
- unscoped metadata-only locations;
- independently pinned nested versions;
- missing canonical pins;
- canonical-version mismatch;
- metadata-only canonical roots;
- partial `resolved` or `integrity` declarations;
- malformed scoped identities;
- nonempty-version enforcement;
- alternate origins and invalid SHA-512 SRI values; and
- all pre-existing npm path, link, lockfile, URL, and integrity cases.

The dedicated quality workflow runs Python 3.10 compilation, Python 3.14 focused tests with 100% production statement and branch coverage, 100% production docstrings, the complete central test suite, and a clean-patch check.

## Incident recovery and rollback

1. Preserve the exact pull-request head SHA, lockfile blob SHA, validation error, and quality-run ID.
2. Determine whether the changed lock is malformed or whether npm produced a supported metadata-only nested location.
3. Never add missing tarball or integrity values by hand. Regenerate the lock with the repository's pinned npm version when the lock is invalid.
4. Roll back only by restoring the prior fail-closed validator or another reviewed implementation that keeps the same identity, version, origin, and integrity controls.
5. Rerun the complete exact-head quality, security, and supply-chain matrix after any repair.

## References

npm, Inc. (2026). *package-lock.json*. npm Docs. https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json

npm, Inc. (2026). *npm install*. npm Docs. https://docs.npmjs.com/cli/v11/commands/npm-install

World Wide Web Consortium. (2016). *Subresource Integrity*. https://www.w3.org/TR/SRI/
Loading
Loading