dsh-standards 0.0.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/40-checker/.github/workflows/plugin-verify.yml +70 -0
- package/40-checker/README.md +251 -0
- package/40-checker/bin/dsh-levels.mjs +15 -0
- package/40-checker/bin/dsh-plugin-verify.mjs +8 -0
- package/40-checker/fixtures/bad/index.mjs +12 -0
- package/40-checker/fixtures/bad/package.json +15 -0
- package/40-checker/fixtures/bad-manifest/index.js +1 -0
- package/40-checker/fixtures/bad-manifest/package.json +5 -0
- package/40-checker/fixtures/bundle/cordis.patch.yml +3 -0
- package/40-checker/fixtures/bundle/package.json +15 -0
- package/40-checker/fixtures/bundle/server.mjs +7 -0
- package/40-checker/fixtures/bundle-v0/cordis.patch.yml +3 -0
- package/40-checker/fixtures/bundle-v0/package.json +21 -0
- package/40-checker/fixtures/bundle-v0/server.mjs +7 -0
- package/40-checker/fixtures/client-missing/client.js +1 -0
- package/40-checker/fixtures/client-missing/index.js +1 -0
- package/40-checker/fixtures/client-missing/package.json +6 -0
- package/40-checker/fixtures/flow-config/index.js +9 -0
- package/40-checker/fixtures/flow-config/package.json +10 -0
- package/40-checker/fixtures/fs-write/index.mjs +7 -0
- package/40-checker/fixtures/fs-write/package.json +10 -0
- package/40-checker/fixtures/good/index.mjs +10 -0
- package/40-checker/fixtures/good/package.json +19 -0
- package/40-checker/fixtures/hang/index.mjs +5 -0
- package/40-checker/fixtures/hang/package.json +10 -0
- package/40-checker/fixtures/known-answer/expected.json +18 -0
- package/40-checker/fixtures/market-index-real.json +18 -0
- package/40-checker/fixtures/market-index.json +18 -0
- package/40-checker/fixtures/negative/bad-entry/package.json +1 -0
- package/40-checker/fixtures/negative/no-entry/package.json +1 -0
- package/40-checker/fixtures/negative/no-patch/package.json +1 -0
- package/40-checker/fixtures/negative/root-missing/cordis.patch.yml +2 -0
- package/40-checker/fixtures/negative/root-missing/package.json +1 -0
- package/40-checker/fixtures/negative/workspace/package.json +1 -0
- package/40-checker/package.json +22 -0
- package/40-checker/results/boost/REPORT.md +304 -0
- package/40-checker/results/boost/lev12458.json +1747 -0
- package/40-checker/results/client/README.md +16 -0
- package/40-checker/results/entry/18/DDDMUC__dsh-free-search.json +381 -0
- package/40-checker/results/entry/18/DDDMUC__dsh-free-search.runtime.json +34 -0
- package/40-checker/results/entry/18/Ebony-Vinyl__dsh-our-free-model.json +361 -0
- package/40-checker/results/entry/18/Ebony-Vinyl__dsh-our-free-model.runtime.json +34 -0
- package/40-checker/results/entry/18/README.md +24 -0
- package/40-checker/results/entry/18/RUNTIME.md +18 -0
- package/40-checker/results/entry/18/SeaOf0__dsh-redteam-model.json +391 -0
- package/40-checker/results/entry/18/YuJunZhiXue__dsh-purge.json +432 -0
- package/40-checker/results/entry/18/ci-diet.json +365 -0
- package/40-checker/results/entry/18/ci-diet.runtime-attempt.json +38 -0
- package/40-checker/results/entry/18/daily-log.json +357 -0
- package/40-checker/results/entry/18/daily-log.runtime.json +519 -0
- package/40-checker/results/entry/18/fullbase/ATTRIBUTION.md +29 -0
- package/40-checker/results/entry/18/fullbase/DDDMUC__dsh-free-search.json +99 -0
- package/40-checker/results/entry/18/fullbase/Ebony-Vinyl__dsh-our-free-model.json +95 -0
- package/40-checker/results/entry/18/fullbase/REPORT.md +261 -0
- package/40-checker/results/entry/18/fullbase/SeaOf0__dsh-redteam-model.json +144 -0
- package/40-checker/results/entry/18/fullbase/YuJunZhiXue__dsh-purge.json +106 -0
- package/40-checker/results/entry/18/fullbase/ci-diet.json +99 -0
- package/40-checker/results/entry/18/fullbase/daily-log.json +94 -0
- package/40-checker/results/entry/18/fullbase/howmp__dsh-pentest.json +104 -0
- package/40-checker/results/entry/18/fullbase/kingcharleslzy-ai__dsh-purge.json +143 -0
- package/40-checker/results/entry/18/fullbase/liguobao__ds-harness-remote.json +134 -0
- package/40-checker/results/entry/18/fullbase/mmparko__dsh-purge.json +138 -0
- package/40-checker/results/entry/18/fullbase/project-memory.json +108 -0
- package/40-checker/results/entry/18/fullbase/qiushi.json +94 -0
- package/40-checker/results/entry/18/fullbase/shaobeichen__dsh-pocket.json +94 -0
- package/40-checker/results/entry/18/fullbase/status-rotator.json +94 -0
- package/40-checker/results/entry/18/fullbase/summary.json +297 -0
- package/40-checker/results/entry/18/fullbase/telemetry.json +94 -0
- package/40-checker/results/entry/18/fullbase/ui-auth.json +94 -0
- package/40-checker/results/entry/18/fullbase/verification.json +94 -0
- package/40-checker/results/entry/18/fullbase/ysr666__dsh-vision-router.json +106 -0
- package/40-checker/results/entry/18/howmp__dsh-pentest.json +361 -0
- package/40-checker/results/entry/18/kingcharleslzy-ai__dsh-purge.json +411 -0
- package/40-checker/results/entry/18/liguobao__ds-harness-remote.json +379 -0
- package/40-checker/results/entry/18/mmparko__dsh-purge.json +441 -0
- package/40-checker/results/entry/18/project-memory.json +361 -0
- package/40-checker/results/entry/18/project-memory.runtime.json +519 -0
- package/40-checker/results/entry/18/qiushi.json +353 -0
- package/40-checker/results/entry/18/qiushi.runtime.json +519 -0
- package/40-checker/results/entry/18/realweb/REPORT.md +73 -0
- package/40-checker/results/entry/18/realweb/SeaOf0__dsh-redteam-model.json +104 -0
- package/40-checker/results/entry/18/realweb/YuJunZhiXue__dsh-purge.json +64 -0
- package/40-checker/results/entry/18/realweb/howmp__dsh-pentest.json +65 -0
- package/40-checker/results/entry/18/realweb/kingcharleslzy-ai__dsh-purge.json +75 -0
- package/40-checker/results/entry/18/realweb/mmparko__dsh-purge.json +70 -0
- package/40-checker/results/entry/18/realweb/shaobeichen__dsh-pocket.json +56 -0
- package/40-checker/results/entry/18/realweb/summary.json +196 -0
- package/40-checker/results/entry/18/realweb/ui-auth.json +56 -0
- package/40-checker/results/entry/18/realweb/ysr666__dsh-vision-router.json +61 -0
- package/40-checker/results/entry/18/richbase/REPORT.md +70 -0
- package/40-checker/results/entry/18/richbase/SeaOf0__dsh-redteam-model.json +61 -0
- package/40-checker/results/entry/18/richbase/SeaOf0__dsh-redteam-model.log +38 -0
- package/40-checker/results/entry/18/shaobeichen__dsh-pocket.json +363 -0
- package/40-checker/results/entry/18/status-rotator.json +362 -0
- package/40-checker/results/entry/18/status-rotator.runtime.json +519 -0
- package/40-checker/results/entry/18/summary.json +266 -0
- package/40-checker/results/entry/18/targetonly/DDDMUC__dsh-free-search.json +34 -0
- package/40-checker/results/entry/18/targetonly/Ebony-Vinyl__dsh-our-free-model.json +34 -0
- package/40-checker/results/entry/18/targetonly/SeaOf0__dsh-redteam-model.json +84 -0
- package/40-checker/results/entry/18/targetonly/YuJunZhiXue__dsh-purge.json +52 -0
- package/40-checker/results/entry/18/targetonly/ci-diet.json +34 -0
- package/40-checker/results/entry/18/targetonly/daily-log.json +34 -0
- package/40-checker/results/entry/18/targetonly/howmp__dsh-pentest.json +46 -0
- package/40-checker/results/entry/18/targetonly/kingcharleslzy-ai__dsh-purge.json +61 -0
- package/40-checker/results/entry/18/targetonly/liguobao__ds-harness-remote.json +39 -0
- package/40-checker/results/entry/18/targetonly/mmparko__dsh-purge.json +57 -0
- package/40-checker/results/entry/18/targetonly/project-memory.json +34 -0
- package/40-checker/results/entry/18/targetonly/qiushi.json +34 -0
- package/40-checker/results/entry/18/targetonly/shaobeichen__dsh-pocket.json +34 -0
- package/40-checker/results/entry/18/targetonly/status-rotator.json +34 -0
- package/40-checker/results/entry/18/targetonly/summary.json +133 -0
- package/40-checker/results/entry/18/targetonly/telemetry.json +34 -0
- package/40-checker/results/entry/18/targetonly/ui-auth.json +34 -0
- package/40-checker/results/entry/18/targetonly/verification.json +34 -0
- package/40-checker/results/entry/18/targetonly/ysr666__dsh-vision-router.json +43 -0
- package/40-checker/results/entry/18/telemetry.json +349 -0
- package/40-checker/results/entry/18/ui-auth.json +369 -0
- package/40-checker/results/entry/18/verification.json +358 -0
- package/40-checker/results/entry/18/ysr666__dsh-vision-router.json +409 -0
- package/40-checker/results/fixtures/bad.json +347 -0
- package/40-checker/results/fixtures/bundle.json +378 -0
- package/40-checker/results/fixtures/good-listing.json +382 -0
- package/40-checker/results/fixtures/good-static.json +322 -0
- package/40-checker/results/fixtures/good.json +375 -0
- package/40-checker/results/fixtures/good.sarif +274 -0
- package/40-checker/results/flow/README.md +19 -0
- package/40-checker/results/flow/j3-j7-fixture.json +51 -0
- package/40-checker/results/flow/j5-j8-client-missing.json +45 -0
- package/40-checker/results/flow/j5-j8-good.json +45 -0
- package/40-checker/results/flow/journey-fixture-bundle.json +90 -0
- package/40-checker/results/flow/journey-fixture-j1-j2-j4-j6.json +107 -0
- package/40-checker/results/flow/real/DDDMUC__dsh-free-search.json +297 -0
- package/40-checker/results/flow/real/REPORT.md +335 -0
- package/40-checker/results/flow/real/YuJunZhiXue__dsh-purge.json +317 -0
- package/40-checker/results/flow/real/ci-diet.json +351 -0
- package/40-checker/results/flow/real/daily-log.json +286 -0
- package/40-checker/results/flow/real/index.json +325 -0
- package/40-checker/results/flow/real/project-memory.json +290 -0
- package/40-checker/results/flow/real/qiushi.json +277 -0
- package/40-checker/results/flow/real/status-rotator.json +275 -0
- package/40-checker/results/flow/real/telemetry.json +178 -0
- package/40-checker/results/flow/real/ui-auth.json +288 -0
- package/40-checker/results/flow/real/verification.json +265 -0
- package/40-checker/results/governance/co-maintainer-packet.md +85 -0
- package/40-checker/results/l1/ci-diet.json +406 -0
- package/40-checker/results/l1/npm-dsh-telemetry-redactor-0.1.0.json +390 -0
- package/40-checker/results/l1/npm-dsh-verification-receipt-0.1.0.json +406 -0
- package/40-checker/results/l1/npm-qiushi-dsh-evidence-audit-0.1.0.json +394 -0
- package/40-checker/results/l1/npm-zzerx-dsh-plugin-daily-log-0.4.3.json +405 -0
- package/40-checker/results/l1/project-memory.json +402 -0
- package/40-checker/results/l1/source-DDDMUC__dsh-free-search.json +422 -0
- package/40-checker/results/l1/source-Ebony-Vinyl__dsh-our-free-model.json +421 -0
- package/40-checker/results/l1/source-SeaOf0__dsh-redteam-model.json +432 -0
- package/40-checker/results/l1/source-YuJunZhiXue__dsh-purge.json +473 -0
- package/40-checker/results/l1/source-howmp__dsh-pentest.json +402 -0
- package/40-checker/results/l1/source-kingcharleslzy-ai__dsh-purge.json +452 -0
- package/40-checker/results/l1/source-liguobao__ds-harness-remote.json +420 -0
- package/40-checker/results/l1/source-mmparko__dsh-purge.json +482 -0
- package/40-checker/results/l1/source-shaobeichen__dsh-pocket.json +404 -0
- package/40-checker/results/l1/source-ysr666__dsh-vision-router.json +384 -0
- package/40-checker/results/l1/status-rotator.json +403 -0
- package/40-checker/results/l1/ui-auth.json +429 -0
- package/40-checker/results/l1/ysr666__dsh-vision-router.published.json +384 -0
- package/40-checker/results/lev3/REPORT.md +342 -0
- package/40-checker/results/lev3/lev3.json +4835 -0
- package/40-checker/results/lev6/REPORT.md +460 -0
- package/40-checker/results/lev6/capture-sample.json +241 -0
- package/40-checker/results/lev6/capture.jsonl +4 -0
- package/40-checker/results/lev6/lev6.json +245 -0
- package/40-checker/results/lev6/replication-r1.json +245 -0
- package/40-checker/results/levels/README.md +16 -0
- package/40-checker/results/levels/dsh-plugin-doctor.json +141 -0
- package/40-checker/results/levels/dsh-plugin-guide.json +136 -0
- package/40-checker/results/m1/dsh-ci-diet-0.5.2.json +352 -0
- package/40-checker/results/m1/dsh-status-rotator-0.38.0.json +349 -0
- package/40-checker/results/m1/dsh-telemetry-redactor-0.1.0.json +336 -0
- package/40-checker/results/m1/dsh-ui-auth-0.7.1.json +356 -0
- package/40-checker/results/m1/dsh-verification-receipt-0.1.0.json +344 -0
- package/40-checker/results/m1/index-level.json +13 -0
- package/40-checker/results/m1/levels.json +72100 -0
- package/40-checker/results/m1/qiushi-dsh-evidence-audit-0.1.0.json +339 -0
- package/40-checker/results/m1/yolk_vat-y-dsh-project-memory-0.6.7.json +348 -0
- package/40-checker/results/m1/zzerx-dsh-plugin-daily-log-0.4.3.json +344 -0
- package/40-checker/results/m2/dsh-ci-diet.json +421 -0
- package/40-checker/results/m2/dsh-ci-diet.unshare-landlock.json +424 -0
- package/40-checker/results/m2/dsh-ci-diet.unshare.json +423 -0
- package/40-checker/results/m2/fixture-bundle.image.json +404 -0
- package/40-checker/results/m2/fixture-bundle.json +392 -0
- package/40-checker/results/m2/fixture-bundle.landlock.json +396 -0
- package/40-checker/results/m2/fixture-bundle.unshare.json +395 -0
- package/40-checker/results/m2/fs-write.json +338 -0
- package/40-checker/results/m2/hang.json +31 -0
- package/40-checker/results/m2/hang.unshare-landlock.json +34 -0
- package/40-checker/results/m2/hang.unshare.json +33 -0
- package/40-checker/results/m2/project-memory.json +417 -0
- package/40-checker/results/m2/status-rotator.json +418 -0
- package/40-checker/results/m2/ui-auth.json +444 -0
- package/40-checker/results/negative/bad-entry.json +345 -0
- package/40-checker/results/negative/no-entry.json +345 -0
- package/40-checker/results/negative/no-patch.json +344 -0
- package/40-checker/results/negative/root-missing.json +344 -0
- package/40-checker/results/negative/root-missing.runtime.json +30 -0
- package/40-checker/results/negative/summary.json +51 -0
- package/40-checker/results/negative/workspace.json +344 -0
- package/40-checker/results/patched/Ebony-Vinyl__dsh-our-free-model.json +334 -0
- package/40-checker/results/patched/Ebony-Vinyl__dsh-our-free-model.overlay.json +335 -0
- package/40-checker/results/patched/SeaOf0__dsh-redteam-model.json +315 -0
- package/40-checker/results/patched/SeaOf0__dsh-redteam-model.overlay.json +316 -0
- package/40-checker/results/patched/mmparko__dsh-purge.json +357 -0
- package/40-checker/results/patched/mmparko__dsh-purge.overlay.json +358 -0
- package/40-checker/results/patched/shaobeichen__dsh-pocket.json +315 -0
- package/40-checker/results/patched/shaobeichen__dsh-pocket.overlay.json +316 -0
- package/40-checker/results/real/DDDMUC__dsh-free-search.json +344 -0
- package/40-checker/results/real/Ebony-Vinyl__dsh-our-free-model.json +343 -0
- package/40-checker/results/real/SeaOf0__dsh-redteam-model.json +354 -0
- package/40-checker/results/real/YuJunZhiXue__dsh-purge.json +395 -0
- package/40-checker/results/real/howmp__dsh-pentest.json +324 -0
- package/40-checker/results/real/kingcharleslzy-ai__dsh-purge.json +374 -0
- package/40-checker/results/real/liguobao__ds-harness-remote.json +342 -0
- package/40-checker/results/real/mmparko__dsh-purge.json +404 -0
- package/40-checker/results/real/shaobeichen__dsh-pocket.json +326 -0
- package/40-checker/results/real/ysr666__dsh-vision-router.json +372 -0
- package/40-checker/results/real/ysr666__dsh-vision-router.listing.json +378 -0
- package/40-checker/results/round-robin/compare.json +52 -0
- package/40-checker/results/round-robin/runner-a.json +9 -0
- package/40-checker/results/round-robin/runner-b.json +9 -0
- package/40-checker/results/sample20/123dbl__dsh-side-session.json +344 -0
- package/40-checker/results/sample20/173787247__dsh-wsl-dns.json +360 -0
- package/40-checker/results/sample20/863683348__dsh-insight.json +375 -0
- package/40-checker/results/sample20/Ansellwan__DSH-Custom-Wallpaper.json +344 -0
- package/40-checker/results/sample20/Jamailar__beav-deepseek-harness.json +341 -0
- package/40-checker/results/sample20/ManoloRemiddi__DSH-Metafolder-Plugin.json +344 -0
- package/40-checker/results/sample20/NEAZ71eve__dsh-tool-github.json +384 -0
- package/40-checker/results/sample20/README.md +3 -0
- package/40-checker/results/sample20/RINGOLINK__dsh-desktop-shell.json +352 -0
- package/40-checker/results/sample20/Zxznb666__dsh-qoder-cn-subagent.json +349 -0
- package/40-checker/results/sample20/agent-mobile__dsh-mobile-gateway.json +353 -0
- package/40-checker/results/sample20/fangqiing__dsh-knowledge-lite.json +359 -0
- package/40-checker/results/sample20/fzy0517__deepseek-harness-session-cleaner.json +344 -0
- package/40-checker/results/sample20/gjy1992__dsh-diagram.json +350 -0
- package/40-checker/results/sample20/mrme000m__dsh-prime-orchestrator.json +414 -0
- package/40-checker/results/sample20/redstonedust__dsh-solidworks-copilot.json +362 -0
- package/40-checker/results/sample20/summary.json +234 -0
- package/40-checker/results/sample20/w2112515__dsh-remote-host.json +344 -0
- package/40-checker/results/sample20/wkfedor__deepseek-harness-voice-input.json +350 -0
- package/40-checker/results/sample20/xfgil__dsh-hot-reloader.json +344 -0
- package/40-checker/results/sample20/yizhiyizhi0128__dsh-peak-scheduler.json +360 -0
- package/40-checker/results/sample20-ci/123dbl__dsh-side-session.json +344 -0
- package/40-checker/results/sample20-ci/173787247__dsh-wsl-dns.json +360 -0
- package/40-checker/results/sample20-ci/863683348__dsh-insight.json +375 -0
- package/40-checker/results/sample20-ci/Ansellwan__DSH-Custom-Wallpaper.json +344 -0
- package/40-checker/results/sample20-ci/Jamailar__beav-deepseek-harness.json +367 -0
- package/40-checker/results/sample20-ci/ManoloRemiddi__DSH-Metafolder-Plugin.json +344 -0
- package/40-checker/results/sample20-ci/NEAZ71eve__dsh-tool-github.json +392 -0
- package/40-checker/results/sample20-ci/README.md +5 -0
- package/40-checker/results/sample20-ci/RINGOLINK__dsh-desktop-shell.json +361 -0
- package/40-checker/results/sample20-ci/Zxznb666__dsh-qoder-cn-subagent.json +349 -0
- package/40-checker/results/sample20-ci/agent-mobile__dsh-mobile-gateway.json +384 -0
- package/40-checker/results/sample20-ci/fangqiing__dsh-knowledge-lite.json +360 -0
- package/40-checker/results/sample20-ci/fzy0517__deepseek-harness-session-cleaner.json +354 -0
- package/40-checker/results/sample20-ci/gjy1992__dsh-diagram.json +381 -0
- package/40-checker/results/sample20-ci/mrme000m__dsh-prime-orchestrator.json +452 -0
- package/40-checker/results/sample20-ci/redstonedust__dsh-solidworks-copilot.json +371 -0
- package/40-checker/results/sample20-ci/summary.json +195 -0
- package/40-checker/results/sample20-ci/w2112515__dsh-remote-host.json +399 -0
- package/40-checker/results/sample20-ci/wkfedor__deepseek-harness-voice-input.json +358 -0
- package/40-checker/results/sample20-ci/xfgil__dsh-hot-reloader.json +344 -0
- package/40-checker/results/sample20-ci/yizhiyizhi0128__dsh-peak-scheduler.json +370 -0
- package/40-checker/results/sample20-ci/zed1902209846-dotcom__DPwhale-plugin.json +231 -0
- package/40-checker/results/sample60/123dbl__dsh-side-session.json +344 -0
- package/40-checker/results/sample60/173787247__dsh-wsl-dns.json +360 -0
- package/40-checker/results/sample60/863683348__dsh-insight.json +375 -0
- package/40-checker/results/sample60/Anionex__dsh-turn-rewind.json +349 -0
- package/40-checker/results/sample60/Ansellwan__DSH-Custom-Wallpaper.json +344 -0
- package/40-checker/results/sample60/Ebony-Vinyl__EAC-Pack.json +352 -0
- package/40-checker/results/sample60/EricWang1358__dsh-web-studyhub.json +376 -0
- package/40-checker/results/sample60/GanyuanRan__Aegis.json +349 -0
- package/40-checker/results/sample60/HiSeax__dsh-codely.json +358 -0
- package/40-checker/results/sample60/Jamailar__beav-deepseek-harness.json +341 -0
- package/40-checker/results/sample60/ManoloRemiddi__DSH-Metafolder-Plugin.json +344 -0
- package/40-checker/results/sample60/MichengAI__dsh-archive-manager.json +357 -0
- package/40-checker/results/sample60/MichengAI__dsh-im-connect.json +347 -0
- package/40-checker/results/sample60/MindLab-Research__dsh-generative-ui.json +350 -0
- package/40-checker/results/sample60/NEAZ71eve__dsh-tool-github.json +384 -0
- package/40-checker/results/sample60/README.md +7 -0
- package/40-checker/results/sample60/RINGOLINK__dsh-desktop-shell.json +352 -0
- package/40-checker/results/sample60/SeanTolstoyevski__dsh-code-review.json +352 -0
- package/40-checker/results/sample60/Tasihi89__dsh-talk-map.json +344 -0
- package/40-checker/results/sample60/Tyan66666__billion-context-dsh.json +469 -0
- package/40-checker/results/sample60/V1ki__dsh-plugin-subscriptions.json +350 -0
- package/40-checker/results/sample60/Yu-tao-Li__dsh-computer-use-win.json +341 -0
- package/40-checker/results/sample60/ZSeven-W__dsh-ios.json +344 -0
- package/40-checker/results/sample60/Zxznb666__dsh-qoder-cn-subagent.json +349 -0
- package/40-checker/results/sample60/agent-mobile__dsh-mobile-gateway.json +353 -0
- package/40-checker/results/sample60/c3cvld7aag__fujiang-dsh.json +361 -0
- package/40-checker/results/sample60/cxzrdxy__dsh-file-explorer.json +389 -0
- package/40-checker/results/sample60/dhicoc__dsh-reverse-skill.json +341 -0
- package/40-checker/results/sample60/fangqiing__dsh-knowledge-lite.json +359 -0
- package/40-checker/results/sample60/fwerkor__local-shell-mcp.json +369 -0
- package/40-checker/results/sample60/fzy0517__deepseek-harness-session-cleaner.json +344 -0
- package/40-checker/results/sample60/gjy1992__dsh-diagram.json +350 -0
- package/40-checker/results/sample60/howmp__dsh-pentest.json +341 -0
- package/40-checker/results/sample60/linhay__harmony-next.skills.json +344 -0
- package/40-checker/results/sample60/liustack__modsearch.json +371 -0
- package/40-checker/results/sample60/mmparko__dsh-purge.json +372 -0
- package/40-checker/results/sample60/mrme000m__dsh-prime-orchestrator.json +414 -0
- package/40-checker/results/sample60/omdsh-dev__dsh_workflow.json +439 -0
- package/40-checker/results/sample60/redstonedust__dsh-solidworks-copilot.json +362 -0
- package/40-checker/results/sample60/seriousz158__dsh-memory.json +350 -0
- package/40-checker/results/sample60/shanliuling__dsh-image-gen.json +353 -0
- package/40-checker/results/sample60/shanliuling__skills-link.json +344 -0
- package/40-checker/results/sample60/shengsheng90__DSH-taskboard.json +341 -0
- package/40-checker/results/sample60/sjh9714__dsh-win32.json +374 -0
- package/40-checker/results/sample60/skymecode__deepseek-harness-for-vscode.json +351 -0
- package/40-checker/results/sample60/sopaco__terrain.json +352 -0
- package/40-checker/results/sample60/summary.json +658 -0
- package/40-checker/results/sample60/tinqiao-oss__engramory.json +352 -0
- package/40-checker/results/sample60/tong-io__tongflow.json +359 -0
- package/40-checker/results/sample60/vibeinging__dsh-desktop.json +382 -0
- package/40-checker/results/sample60/w2112515__dsh-remote-host.json +344 -0
- package/40-checker/results/sample60/wkfedor__deepseek-harness-voice-input.json +350 -0
- package/40-checker/results/sample60/wz20__dsh-dafeiyu-dot.json +349 -0
- package/40-checker/results/sample60/xfgil__dsh-hot-reloader.json +344 -0
- package/40-checker/results/sample60/yi-yezhiqiu__dsh-prompt-market.json +360 -0
- package/40-checker/results/sample60/yizhiyizhi0128__dsh-peak-scheduler.json +360 -0
- package/40-checker/results/sample60/yjh051108__dsh-routing-suite.json +366 -0
- package/40-checker/results/sample60-ci/123dbl__dsh-side-session.json +344 -0
- package/40-checker/results/sample60-ci/173787247__dsh-wsl-dns.json +360 -0
- package/40-checker/results/sample60-ci/863683348__dsh-insight.json +375 -0
- package/40-checker/results/sample60-ci/Anionex__dsh-turn-rewind.json +379 -0
- package/40-checker/results/sample60-ci/Ansellwan__DSH-Custom-Wallpaper.json +344 -0
- package/40-checker/results/sample60-ci/Ebony-Vinyl__EAC-Pack.json +362 -0
- package/40-checker/results/sample60-ci/EricWang1358__dsh-web-studyhub.json +378 -0
- package/40-checker/results/sample60-ci/GanyuanRan__Aegis.json +349 -0
- package/40-checker/results/sample60-ci/HiSeax__dsh-codely.json +368 -0
- package/40-checker/results/sample60-ci/Jamailar__beav-deepseek-harness.json +367 -0
- package/40-checker/results/sample60-ci/LiarMTTT__TavernWeave.json +231 -0
- package/40-checker/results/sample60-ci/ManoloRemiddi__DSH-Metafolder-Plugin.json +344 -0
- package/40-checker/results/sample60-ci/MichengAI__dsh-archive-manager.json +395 -0
- package/40-checker/results/sample60-ci/MichengAI__dsh-im-connect.json +404 -0
- package/40-checker/results/sample60-ci/MindLab-Research__dsh-generative-ui.json +410 -0
- package/40-checker/results/sample60-ci/NEAZ71eve__dsh-tool-github.json +392 -0
- package/40-checker/results/sample60-ci/README.md +7 -0
- package/40-checker/results/sample60-ci/RINGOLINK__dsh-desktop-shell.json +361 -0
- package/40-checker/results/sample60-ci/Ruler4396__dsh-launcher.json +231 -0
- package/40-checker/results/sample60-ci/SeanTolstoyevski__dsh-code-review.json +363 -0
- package/40-checker/results/sample60-ci/Tasihi89__dsh-talk-map.json +372 -0
- package/40-checker/results/sample60-ci/Tyan66666__billion-context-dsh.json +469 -0
- package/40-checker/results/sample60-ci/V1ki__dsh-plugin-subscriptions.json +368 -0
- package/40-checker/results/sample60-ci/Yu-tao-Li__dsh-computer-use-win.json +349 -0
- package/40-checker/results/sample60-ci/ZSeven-W__dsh-ios.json +344 -0
- package/40-checker/results/sample60-ci/Zxznb666__dsh-qoder-cn-subagent.json +349 -0
- package/40-checker/results/sample60-ci/agent-mobile__dsh-mobile-gateway.json +384 -0
- package/40-checker/results/sample60-ci/c3cvld7aag__fujiang-dsh.json +361 -0
- package/40-checker/results/sample60-ci/cxzrdxy__dsh-file-explorer.json +399 -0
- package/40-checker/results/sample60-ci/dhicoc__dsh-reverse-skill.json +352 -0
- package/40-checker/results/sample60-ci/fangqiing__dsh-knowledge-lite.json +360 -0
- package/40-checker/results/sample60-ci/fwerkor__local-shell-mcp.json +387 -0
- package/40-checker/results/sample60-ci/fzy0517__deepseek-harness-session-cleaner.json +354 -0
- package/40-checker/results/sample60-ci/gjy1992__dsh-diagram.json +381 -0
- package/40-checker/results/sample60-ci/howmp__dsh-pentest.json +361 -0
- package/40-checker/results/sample60-ci/linhay__harmony-next.skills.json +344 -0
- package/40-checker/results/sample60-ci/liustack__modsearch.json +382 -0
- package/40-checker/results/sample60-ci/mmparko__dsh-purge.json +441 -0
- package/40-checker/results/sample60-ci/mrme000m__dsh-prime-orchestrator.json +452 -0
- package/40-checker/results/sample60-ci/omdsh-dev__dsh_workflow.json +439 -0
- package/40-checker/results/sample60-ci/plastic-labs__honcho.json +231 -0
- package/40-checker/results/sample60-ci/redstonedust__dsh-solidworks-copilot.json +371 -0
- package/40-checker/results/sample60-ci/seriousz158__dsh-memory.json +351 -0
- package/40-checker/results/sample60-ci/shanliuling__dsh-image-gen.json +382 -0
- package/40-checker/results/sample60-ci/shanliuling__skills-link.json +344 -0
- package/40-checker/results/sample60-ci/shengsheng90__DSH-taskboard.json +370 -0
- package/40-checker/results/sample60-ci/sjh9714__dsh-win32.json +410 -0
- package/40-checker/results/sample60-ci/skymecode__deepseek-harness-for-vscode.json +391 -0
- package/40-checker/results/sample60-ci/sopaco__deepwiki-rs.json +231 -0
- package/40-checker/results/sample60-ci/sopaco__terrain.json +352 -0
- package/40-checker/results/sample60-ci/summary.json +555 -0
- package/40-checker/results/sample60-ci/tinqiao-oss__engramory.json +362 -0
- package/40-checker/results/sample60-ci/tong-io__tongflow.json +393 -0
- package/40-checker/results/sample60-ci/vibeinging__dsh-desktop.json +555 -0
- package/40-checker/results/sample60-ci/w2112515__dsh-remote-host.json +399 -0
- package/40-checker/results/sample60-ci/wkfedor__deepseek-harness-voice-input.json +358 -0
- package/40-checker/results/sample60-ci/wz20__dsh-dafeiyu-dot.json +390 -0
- package/40-checker/results/sample60-ci/xfgil__dsh-hot-reloader.json +344 -0
- package/40-checker/results/sample60-ci/yi-yezhiqiu__dsh-prompt-market.json +373 -0
- package/40-checker/results/sample60-ci/yizhiyizhi0128__dsh-peak-scheduler.json +370 -0
- package/40-checker/results/sample60-ci/yjh051108__dsh-routing-suite.json +437 -0
- package/40-checker/results/sample60-ci/zed1902209846-dotcom__DPwhale-plugin.json +231 -0
- package/40-checker/results/triage/REPORT.md +317 -0
- package/40-checker/results/triage/evidence/g2-rejections.txt +63 -0
- package/40-checker/results/triage/evidence/purge-baseline-0.2.1-rc.5.json +51 -0
- package/40-checker/results/triage/evidence/purge-baseline-0.2.2-alpha.2.json +51 -0
- package/40-checker/results/triage/evidence/purge-postinstall.txt +62 -0
- package/40-checker/results/triage/evidence/purge-with-profile-0.2.1-rc.5.json +71 -0
- package/40-checker/results/triage/evidence/purge-with-profile-0.2.2-alpha.2.json +71 -0
- package/40-checker/results/triage/evidence/semver-matrix.json +32 -0
- package/40-checker/results/triage/triage.json +295 -0
- package/40-checker/results/webapp/README.md +10 -0
- package/40-checker/results/webapp/summary.json +46 -0
- package/40-checker/results/webapp/web-auth.json +19 -0
- package/40-checker/results/webruntime/DDDMUC__dsh-free-search/client-export.json +7 -0
- package/40-checker/results/webruntime/DDDMUC__dsh-free-search/installed-package.json +123 -0
- package/40-checker/results/webruntime/DDDMUC__dsh-free-search/probe.json +129 -0
- package/40-checker/results/webruntime/DDDMUC__dsh-free-search/shot.png +0 -0
- package/40-checker/results/webruntime/DDDMUC__dsh-free-search/summary.md +16 -0
- package/40-checker/results/webruntime/Ebony-Vinyl__dsh-our-free-model/client-export.json +7 -0
- package/40-checker/results/webruntime/Ebony-Vinyl__dsh-our-free-model/installed-package.json +76 -0
- package/40-checker/results/webruntime/Ebony-Vinyl__dsh-our-free-model/probe.json +129 -0
- package/40-checker/results/webruntime/Ebony-Vinyl__dsh-our-free-model/shot.png +0 -0
- package/40-checker/results/webruntime/Ebony-Vinyl__dsh-our-free-model/summary.md +16 -0
- package/40-checker/results/webruntime/REPORT.md +253 -0
- package/40-checker/results/webruntime/SeaOf0__dsh-redteam-model/client-export.json +7 -0
- package/40-checker/results/webruntime/SeaOf0__dsh-redteam-model/installed-package.json +97 -0
- package/40-checker/results/webruntime/SeaOf0__dsh-redteam-model/probe.json +129 -0
- package/40-checker/results/webruntime/SeaOf0__dsh-redteam-model/shot.png +0 -0
- package/40-checker/results/webruntime/SeaOf0__dsh-redteam-model/summary.md +16 -0
- package/40-checker/results/webruntime/YuJunZhiXue__dsh-purge/client-export.json +7 -0
- package/40-checker/results/webruntime/YuJunZhiXue__dsh-purge/installed-package.json +98 -0
- package/40-checker/results/webruntime/YuJunZhiXue__dsh-purge/probe.json +136 -0
- package/40-checker/results/webruntime/YuJunZhiXue__dsh-purge/shot.png +0 -0
- package/40-checker/results/webruntime/YuJunZhiXue__dsh-purge/summary.md +16 -0
- package/40-checker/results/webruntime/ci-diet/client-export.json +10 -0
- package/40-checker/results/webruntime/ci-diet/installed-package.json +100 -0
- package/40-checker/results/webruntime/ci-diet/probe.json +129 -0
- package/40-checker/results/webruntime/ci-diet/shot.png +0 -0
- package/40-checker/results/webruntime/ci-diet/summary.md +16 -0
- package/40-checker/results/webruntime/daily-log/client-export.json +10 -0
- package/40-checker/results/webruntime/daily-log/installed-package.json +113 -0
- package/40-checker/results/webruntime/daily-log/probe.json +129 -0
- package/40-checker/results/webruntime/daily-log/shot.png +0 -0
- package/40-checker/results/webruntime/daily-log/summary.md +16 -0
- package/40-checker/results/webruntime/howmp__dsh-pentest/client-export.json +7 -0
- package/40-checker/results/webruntime/howmp__dsh-pentest/installed-package.json +90 -0
- package/40-checker/results/webruntime/howmp__dsh-pentest/probe.json +129 -0
- package/40-checker/results/webruntime/howmp__dsh-pentest/shot.png +0 -0
- package/40-checker/results/webruntime/howmp__dsh-pentest/summary.md +16 -0
- package/40-checker/results/webruntime/kingcharleslzy-ai__dsh-purge/client-export.json +7 -0
- package/40-checker/results/webruntime/kingcharleslzy-ai__dsh-purge/installed-package.json +164 -0
- package/40-checker/results/webruntime/kingcharleslzy-ai__dsh-purge/probe.json +129 -0
- package/40-checker/results/webruntime/kingcharleslzy-ai__dsh-purge/shot.png +0 -0
- package/40-checker/results/webruntime/kingcharleslzy-ai__dsh-purge/summary.md +16 -0
- package/40-checker/results/webruntime/liguobao__ds-harness-remote/client-export.json +7 -0
- package/40-checker/results/webruntime/liguobao__ds-harness-remote/installed-package.json +166 -0
- package/40-checker/results/webruntime/liguobao__ds-harness-remote/probe.json +129 -0
- package/40-checker/results/webruntime/liguobao__ds-harness-remote/shot.png +0 -0
- package/40-checker/results/webruntime/liguobao__ds-harness-remote/summary.md +16 -0
- package/40-checker/results/webruntime/local-pre-ci/README.md +67 -0
- package/40-checker/results/webruntime/local-pre-ci/client-exports.json +158 -0
- package/40-checker/results/webruntime/local-pre-ci/dsh-free-search.probe.json +119 -0
- package/40-checker/results/webruntime/local-pre-ci/dsh-pocket.probe.json +119 -0
- package/40-checker/results/webruntime/local-pre-ci/dsh-redteam-model.probe.json +119 -0
- package/40-checker/results/webruntime/local-pre-ci/qiushi-shell-only.probe.json +104 -0
- package/40-checker/results/webruntime/local-pre-ci/ui-auth-no-login.fail.json +52 -0
- package/40-checker/results/webruntime/local-pre-ci/ui-auth.probe.json +123 -0
- package/40-checker/results/webruntime/mmparko__dsh-purge/client-export.json +7 -0
- package/40-checker/results/webruntime/mmparko__dsh-purge/installed-package.json +95 -0
- package/40-checker/results/webruntime/mmparko__dsh-purge/probe.json +136 -0
- package/40-checker/results/webruntime/mmparko__dsh-purge/shot.png +0 -0
- package/40-checker/results/webruntime/mmparko__dsh-purge/summary.md +16 -0
- package/40-checker/results/webruntime/project-memory/client-export.json +7 -0
- package/40-checker/results/webruntime/project-memory/installed-package.json +118 -0
- package/40-checker/results/webruntime/project-memory/probe.json +129 -0
- package/40-checker/results/webruntime/project-memory/shot.png +0 -0
- package/40-checker/results/webruntime/project-memory/summary.md +16 -0
- package/40-checker/results/webruntime/qiushi/client-export.json +7 -0
- package/40-checker/results/webruntime/qiushi/installed-package.json +84 -0
- package/40-checker/results/webruntime/qiushi/probe.json +114 -0
- package/40-checker/results/webruntime/qiushi/shot.png +0 -0
- package/40-checker/results/webruntime/qiushi/summary.md +16 -0
- package/40-checker/results/webruntime/shaobeichen__dsh-pocket/client-export.json +7 -0
- package/40-checker/results/webruntime/shaobeichen__dsh-pocket/installed-package.json +85 -0
- package/40-checker/results/webruntime/shaobeichen__dsh-pocket/probe.json +129 -0
- package/40-checker/results/webruntime/shaobeichen__dsh-pocket/shot.png +0 -0
- package/40-checker/results/webruntime/shaobeichen__dsh-pocket/summary.md +16 -0
- package/40-checker/results/webruntime/status-rotator/client-export.json +7 -0
- package/40-checker/results/webruntime/status-rotator/installed-package.json +107 -0
- package/40-checker/results/webruntime/status-rotator/probe.json +129 -0
- package/40-checker/results/webruntime/status-rotator/shot.png +0 -0
- package/40-checker/results/webruntime/status-rotator/summary.md +16 -0
- package/40-checker/results/webruntime/summary.json +323 -0
- package/40-checker/results/webruntime/telemetry/probe.json +20 -0
- package/40-checker/results/webruntime/telemetry/summary.md +4 -0
- package/40-checker/results/webruntime/ui-auth/client-export.json +7 -0
- package/40-checker/results/webruntime/ui-auth/installed-package.json +94 -0
- package/40-checker/results/webruntime/ui-auth/probe.json +129 -0
- package/40-checker/results/webruntime/ui-auth/shot.png +0 -0
- package/40-checker/results/webruntime/ui-auth/summary.md +16 -0
- package/40-checker/results/webruntime/verification/probe.json +20 -0
- package/40-checker/results/webruntime/verification/summary.md +4 -0
- package/40-checker/results/webruntime/ysr666__dsh-vision-router/client-export.json +7 -0
- package/40-checker/results/webruntime/ysr666__dsh-vision-router/installed-package.json +142 -0
- package/40-checker/results/webruntime/ysr666__dsh-vision-router/probe.json +129 -0
- package/40-checker/results/webruntime/ysr666__dsh-vision-router/shot.png +0 -0
- package/40-checker/results/webruntime/ysr666__dsh-vision-router/summary.md +16 -0
- package/40-checker/samples/README.md +8 -0
- package/40-checker/samples/entry18.json +139 -0
- package/40-checker/samples/frame.json +485 -0
- package/40-checker/scripts/apply-overlay.mjs +59 -0
- package/40-checker/scripts/attestation-check.mjs +151 -0
- package/40-checker/scripts/bundle-smoke.mjs +126 -0
- package/40-checker/scripts/claim-check.mjs +145 -0
- package/40-checker/scripts/clause-map.mjs +94 -0
- package/40-checker/scripts/collect-fixtures.mjs +44 -0
- package/40-checker/scripts/dashboard.mjs +85 -0
- package/40-checker/scripts/dco-check.mjs +147 -0
- package/40-checker/scripts/dependabot-check.mjs +40 -0
- package/40-checker/scripts/doc-commands-check.mjs +92 -0
- package/40-checker/scripts/entry-scan.mjs +190 -0
- package/40-checker/scripts/entry-validate.mjs +291 -0
- package/40-checker/scripts/entry18-attribution.mjs +66 -0
- package/40-checker/scripts/entry18-ci.mjs +685 -0
- package/40-checker/scripts/entry18-realweb-summary.mjs +71 -0
- package/40-checker/scripts/entry18-web.mjs +307 -0
- package/40-checker/scripts/evidence-chain.mjs +100 -0
- package/40-checker/scripts/flow-index.mjs +82 -0
- package/40-checker/scripts/flow-sample-ci.mjs +529 -0
- package/40-checker/scripts/governance-check.mjs +210 -0
- package/40-checker/scripts/host-farm.mjs +165 -0
- package/40-checker/scripts/journey-config-observe.mjs +109 -0
- package/40-checker/scripts/journey-disclosure-shape.mjs +83 -0
- package/40-checker/scripts/journey-runtime.mjs +178 -0
- package/40-checker/scripts/journey.mjs +76 -0
- package/40-checker/scripts/label-drift.mjs +74 -0
- package/40-checker/scripts/label-sync.mjs +87 -0
- package/40-checker/scripts/label-verify.mjs +90 -0
- package/40-checker/scripts/landlock-exec.c +101 -0
- package/40-checker/scripts/level-audit.mjs +336 -0
- package/40-checker/scripts/m1-sidecar.mjs +126 -0
- package/40-checker/scripts/m2-runner.mjs +213 -0
- package/40-checker/scripts/round-robin.mjs +88 -0
- package/40-checker/scripts/sample-frame.mjs +72 -0
- package/40-checker/scripts/sample20-ci.mjs +25 -0
- package/40-checker/scripts/sample60-ci.mjs +25 -0
- package/40-checker/scripts/stale-check.mjs +59 -0
- package/40-checker/scripts/surveillance.mjs +88 -0
- package/40-checker/scripts/web-probe.mjs +504 -0
- package/40-checker/src/cli.mjs +300 -0
- package/40-checker/src/client-shape.mjs +37 -0
- package/40-checker/src/declarations.mjs +242 -0
- package/40-checker/src/index.mjs +8 -0
- package/40-checker/src/install-spec.mjs +67 -0
- package/40-checker/src/label.mjs +130 -0
- package/40-checker/src/manifest.mjs +364 -0
- package/40-checker/src/permissions.mjs +60 -0
- package/40-checker/src/report.mjs +204 -0
- package/40-checker/src/result.mjs +60 -0
- package/40-checker/src/runtime.mjs +299 -0
- package/40-checker/src/semver.mjs +128 -0
- package/40-checker/src/util.mjs +148 -0
- package/40-checker/test/attestation.test.mjs +59 -0
- package/40-checker/test/checks.test.mjs +172 -0
- package/40-checker/test/claim.test.mjs +28 -0
- package/40-checker/test/client-shape.test.mjs +35 -0
- package/40-checker/test/dco.test.mjs +51 -0
- package/40-checker/test/entry-validate.test.mjs +172 -0
- package/40-checker/test/governance.test.mjs +76 -0
- package/40-checker/test/label.test.mjs +97 -0
- package/40-checker/test/level-audit.test.mjs +99 -0
- package/40-checker/test/levels.test.mjs +31 -0
- package/40-checker/test/ops.test.mjs +117 -0
- package/40-checker/test/permissions.test.mjs +40 -0
- package/40-checker/test/semver.test.mjs +32 -0
- package/40-checker/test/verify.test.mjs +57 -0
- package/LICENSE +28 -0
- package/LICENSE-APACHE +190 -0
- package/LICENSE-CC-BY +23 -0
- package/NOTICE.md +11 -0
- package/README.md +146 -3
- package/bin/dsh-levels.mjs +4 -0
- package/bin/dsh-standards.mjs +18 -0
- package/docs/BOOST-FIXTURES-2026-11-02.md +38 -0
- package/docs/DEVELOPER-JOURNEY.md +40 -0
- package/docs/HOST-J3-BUG-REPORT-DRAFT.md +27 -0
- package/docs/HOST-J3-CONFIG-REPRO-2026-11-02.md +36 -0
- package/docs/NAMING-FALLBACK.md +11 -0
- package/docs/fork-policy.md +12 -0
- package/docs/full-test-plan-2026-11-02.md +207 -0
- package/docs/incident.md +37 -0
- package/docs/onboarding.md +27 -0
- package/docs/privacy.md +12 -0
- package/docs/release.md +16 -0
- package/docs/scope-security.md +62 -0
- package/docs/status-taxonomy.md +54 -0
- package/docs/sunset.md +44 -0
- package/docs/translating.md +12 -0
- package/package.json +49 -12
- package/spec/README.md +27 -0
- package/spec/boost/README.md +8 -0
- package/spec/clauses.json +253 -0
- package/spec/entry/README.md +9 -0
- package/spec/flow/README.md +8 -0
- package/spec/levels.json +371 -0
- package/spec/levels.schema.json +45 -0
- package/spec/reference-suite.json +35 -0
- package/spec/schemas/attestation.schema.json +284 -0
- package/spec/schemas/evidence.schema.json +331 -0
- package/spec/schemas/report.schema.json +64 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal SemVer range matcher for the checker.
|
|
3
|
+
*
|
|
4
|
+
* It is intentionally small: the host evaluates plugin requirements with
|
|
5
|
+
* `semver.satisfies(runtime, range, { includePrerelease: true })`
|
|
6
|
+
* (deepseek-harness/packages/boot/app-boot/src/plugin-compatibility.ts:52).
|
|
7
|
+
* This module implements the subset that appears in package manifests:
|
|
8
|
+
* exact versions, `>= > <= <`, `^`, `~`, `*`/`x`, space-separated AND,
|
|
9
|
+
* and `||` alternatives. It does NOT implement hyphen ranges, `!=`,
|
|
10
|
+
* or npm's "prerelease only matches same tuple" exclusion; the host uses
|
|
11
|
+
* includePrerelease, so we include prereleases everywhere.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/
|
|
15
|
+
|
|
16
|
+
export function parseVersion(value) {
|
|
17
|
+
if (typeof value !== 'string') return null
|
|
18
|
+
const match = VERSION_RE.exec(value.trim())
|
|
19
|
+
if (!match) return null
|
|
20
|
+
return {
|
|
21
|
+
major: Number(match[1]),
|
|
22
|
+
minor: Number(match[2]),
|
|
23
|
+
patch: Number(match[3]),
|
|
24
|
+
prerelease: match[4] ? match[4].split('.') : [],
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function compareIdentifier(left, right) {
|
|
29
|
+
const leftNumeric = /^\d+$/.test(left)
|
|
30
|
+
const rightNumeric = /^\d+$/.test(right)
|
|
31
|
+
if (leftNumeric && rightNumeric) return Number(left) - Number(right)
|
|
32
|
+
if (leftNumeric) return -1
|
|
33
|
+
if (rightNumeric) return 1
|
|
34
|
+
return left < right ? -1 : left > right ? 1 : 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function compareVersions(left, right) {
|
|
38
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
39
|
+
if (left[key] !== right[key]) return left[key] - right[key]
|
|
40
|
+
}
|
|
41
|
+
const a = left.prerelease
|
|
42
|
+
const b = right.prerelease
|
|
43
|
+
if (a.length === 0 && b.length === 0) return 0
|
|
44
|
+
if (a.length === 0) return 1
|
|
45
|
+
if (b.length === 0) return -1
|
|
46
|
+
const length = Math.max(a.length, b.length)
|
|
47
|
+
for (let index = 0; index < length; index += 1) {
|
|
48
|
+
if (a[index] === undefined) return -1
|
|
49
|
+
if (b[index] === undefined) return 1
|
|
50
|
+
const result = compareIdentifier(a[index], b[index])
|
|
51
|
+
if (result !== 0) return result
|
|
52
|
+
}
|
|
53
|
+
return 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function upperForCaret(version) {
|
|
57
|
+
if (version.major > 0) return { ...version, major: version.major + 1, minor: 0, patch: 0, prerelease: [] }
|
|
58
|
+
if (version.minor > 0) return { ...version, minor: version.minor + 1, patch: 0, prerelease: [] }
|
|
59
|
+
return { ...version, patch: version.patch + 1, prerelease: [] }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function upperForTilde(version) {
|
|
63
|
+
return { ...version, minor: version.minor + 1, patch: 0, prerelease: [] }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function tokenizeAlternative(alternative) {
|
|
67
|
+
const tokens = []
|
|
68
|
+
const text = alternative.trim()
|
|
69
|
+
if (text === '' || text === '*' || text === 'x' || text === 'X') return [{ op: '*', version: null }]
|
|
70
|
+
// Insert a space between a comparator and its version when written as ">=1.2.3"
|
|
71
|
+
// (already no space) and split on whitespace.
|
|
72
|
+
for (const raw of text.split(/\s+/)) {
|
|
73
|
+
let token = raw
|
|
74
|
+
if (token === '*' || token === 'x' || token === 'X') {
|
|
75
|
+
tokens.push({ op: '*', version: null })
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
const match = /^(>=|<=|>|<|=|\^|~)?\s*v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)$/.exec(token)
|
|
79
|
+
if (!match) return null
|
|
80
|
+
const op = match[1] ?? '='
|
|
81
|
+
const version = parseVersion(match[2])
|
|
82
|
+
if (!version) return null
|
|
83
|
+
tokens.push({ op, version })
|
|
84
|
+
}
|
|
85
|
+
return tokens
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function satisfiesToken(version, token) {
|
|
89
|
+
if (token.op === '*') return true
|
|
90
|
+
const cmp = compareVersions(version, token.version)
|
|
91
|
+
switch (token.op) {
|
|
92
|
+
case '=': return cmp === 0
|
|
93
|
+
case '>': return cmp > 0
|
|
94
|
+
case '>=': return cmp >= 0
|
|
95
|
+
case '<': return cmp < 0
|
|
96
|
+
case '<=': return cmp <= 0
|
|
97
|
+
case '^': return cmp >= 0 && compareVersions(version, upperForCaret(token.version)) < 0
|
|
98
|
+
case '~': return cmp >= 0 && compareVersions(version, upperForTilde(token.version)) < 0
|
|
99
|
+
default: return false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param {string} version exact version to test
|
|
105
|
+
* @param {string} range SemVer range
|
|
106
|
+
* @returns {boolean}
|
|
107
|
+
*/
|
|
108
|
+
export function satisfies(version, range) {
|
|
109
|
+
const parsed = parseVersion(version)
|
|
110
|
+
if (!parsed || typeof range !== 'string') return false
|
|
111
|
+
if (range.trim() === '') return false
|
|
112
|
+
const alternatives = range.split('||')
|
|
113
|
+
for (const alternative of alternatives) {
|
|
114
|
+
const tokens = tokenizeAlternative(alternative)
|
|
115
|
+
if (!tokens || tokens.length === 0) continue
|
|
116
|
+
if (tokens.every(token => satisfiesToken(parsed, token))) return true
|
|
117
|
+
}
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @returns {boolean} whether `range` is a syntactically usable range for this checker. */
|
|
122
|
+
export function validRange(range) {
|
|
123
|
+
if (typeof range !== 'string' || range.trim() === '') return false
|
|
124
|
+
for (const alternative of range.split('||')) {
|
|
125
|
+
if (!tokenizeAlternative(alternative)) return false
|
|
126
|
+
}
|
|
127
|
+
return true
|
|
128
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const SOURCE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.jsx'])
|
|
5
|
+
|
|
6
|
+
export function exists(target) {
|
|
7
|
+
try { fs.accessSync(target); return true } catch { return false }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isFile(target) {
|
|
11
|
+
try { return fs.statSync(target).isFile() } catch { return false }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isDirectory(target) {
|
|
15
|
+
try { return fs.statSync(target).isDirectory() } catch { return false }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function readText(target) {
|
|
19
|
+
return fs.readFileSync(target, 'utf8')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function readJson(target) {
|
|
23
|
+
return JSON.parse(readText(target))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function readJsonMaybe(target) {
|
|
27
|
+
try { return { value: readJson(target), error: null } } catch (error) {
|
|
28
|
+
return { value: null, error }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isObject(value) {
|
|
33
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function asArray(value) {
|
|
37
|
+
if (value === undefined || value === null) return []
|
|
38
|
+
return Array.isArray(value) ? value : [value]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function escapeRegExp(value) {
|
|
42
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function posixRelative(from, to) {
|
|
46
|
+
return path.relative(from, to).split(path.sep).join('/')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const SKIP_DIRECTORIES = new Set([
|
|
50
|
+
'node_modules', '.git', '.hg', '.svn', 'test', 'tests', '__tests__', 'docs', 'doc',
|
|
51
|
+
'assets', 'images', 'screenshots', 'coverage', '.github', '.agents', '.claude',
|
|
52
|
+
'tools', 'scripts', 'examples', 'benchmarks', 'fixtures', 'demo', 'dev', 'deploy', 'quality', 'bench',
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
const BUILD_FILE = /(?:^|\/)(?:build|esbuild|vite|rollup|webpack)\.config\.[cm]?[jt]s$|(?:^|\/)(?:build|esbuild)\.mjs$|(?:^|\/)(?:make|render|verify|check)-[^/]+\.mjs$/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Collect source files without following symlinks. Deterministic order, bounded.
|
|
59
|
+
* @param {string} root
|
|
60
|
+
* @param {{maxFiles?: number, maxBytes?: number}} [options]
|
|
61
|
+
*/
|
|
62
|
+
export function listSourceFiles(root, options = {}) {
|
|
63
|
+
const maxFiles = options.maxFiles ?? 400
|
|
64
|
+
const maxBytes = options.maxBytes ?? 2_000_000
|
|
65
|
+
const files = []
|
|
66
|
+
let bytes = 0
|
|
67
|
+
const walk = (directory) => {
|
|
68
|
+
if (files.length >= maxFiles || bytes >= maxBytes) return
|
|
69
|
+
let entries
|
|
70
|
+
try { entries = fs.readdirSync(directory, { withFileTypes: true }) } catch { return }
|
|
71
|
+
entries.sort((a, b) => a.name.localeCompare(b.name))
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
if (files.length >= maxFiles || bytes >= maxBytes) return
|
|
74
|
+
const absolute = path.join(directory, entry.name)
|
|
75
|
+
if (entry.isDirectory()) {
|
|
76
|
+
if (SKIP_DIRECTORIES.has(entry.name)) continue
|
|
77
|
+
if (entry.name.startsWith('.')) continue
|
|
78
|
+
walk(absolute)
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
if (!entry.isFile()) continue
|
|
82
|
+
if (!SOURCE_EXTENSIONS.has(path.extname(entry.name))) continue
|
|
83
|
+
const relative = path.relative(root, absolute).split(path.sep).join('/')
|
|
84
|
+
if (BUILD_FILE.test(relative)) continue
|
|
85
|
+
let size = 0
|
|
86
|
+
try { size = fs.statSync(absolute).size } catch { continue }
|
|
87
|
+
if (bytes + size > maxBytes) continue
|
|
88
|
+
bytes += size
|
|
89
|
+
files.push(absolute)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
walk(root)
|
|
93
|
+
return files
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Read all source files once, returning {file, relative, text} records. */
|
|
97
|
+
export function readSources(root, options) {
|
|
98
|
+
return listSourceFiles(root, options).map(file => ({
|
|
99
|
+
file,
|
|
100
|
+
relative: posixRelative(root, file),
|
|
101
|
+
text: readText(file),
|
|
102
|
+
}))
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function regexHits(sources, pattern) {
|
|
106
|
+
const hits = []
|
|
107
|
+
for (const source of sources) {
|
|
108
|
+
const re = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`)
|
|
109
|
+
let match
|
|
110
|
+
while ((match = re.exec(source.text))) {
|
|
111
|
+
const before = source.text.slice(0, match.index)
|
|
112
|
+
const line = before.split('\n').length
|
|
113
|
+
hits.push({ file: source.relative, line, text: match[0] })
|
|
114
|
+
if (match[0] === '') re.lastIndex += 1
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return hits
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Resolve an exports target for the root subpath. Returns a relative path or null. */
|
|
121
|
+
export function rootExportTarget(manifest) {
|
|
122
|
+
const exportsField = manifest.exports
|
|
123
|
+
if (exportsField === undefined) return null
|
|
124
|
+
const pick = (value) => {
|
|
125
|
+
if (typeof value === 'string') return value
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
for (const item of value) {
|
|
128
|
+
const picked = pick(item)
|
|
129
|
+
if (picked) return picked
|
|
130
|
+
}
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
if (!isObject(value)) return null
|
|
134
|
+
for (const key of ['import', 'default', 'node', 'require', 'module-sync', 'browser']) {
|
|
135
|
+
if (Object.hasOwn(value, key)) {
|
|
136
|
+
const picked = pick(value[key])
|
|
137
|
+
if (picked) return picked
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
if (typeof exportsField === 'string' || Array.isArray(exportsField)) return pick(exportsField)
|
|
143
|
+
if (!isObject(exportsField)) return null
|
|
144
|
+
if (Object.hasOwn(exportsField, '.')) return pick(exportsField['.'])
|
|
145
|
+
// A conditional object without subpath keys is the root export.
|
|
146
|
+
if (Object.hasOwn(exportsField, 'import') || Object.hasOwn(exportsField, 'default') || Object.hasOwn(exportsField, 'require')) return pick(exportsField)
|
|
147
|
+
return null
|
|
148
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { validateAttestation } from '../scripts/attestation-check.mjs'
|
|
7
|
+
|
|
8
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const ROOT = path.resolve(HERE, '..', '..')
|
|
10
|
+
const base = () => JSON.parse(fs.readFileSync(path.join(ROOT, 'publish/attestations/DSH-ATT-2026-001.json'), 'utf8'))
|
|
11
|
+
|
|
12
|
+
test('attestation: the checked-in example passes', () => {
|
|
13
|
+
const result = validateAttestation(base())
|
|
14
|
+
assert.deepEqual(result.errors, [])
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('attestation: a level field is forbidden', () => {
|
|
18
|
+
const cert = base()
|
|
19
|
+
cert.level = 'entry'
|
|
20
|
+
const result = validateAttestation(cert)
|
|
21
|
+
assert.ok(result.errors.some((e) => /level field/.test(e)))
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('attestation: selfAssessed cannot be verified', () => {
|
|
25
|
+
const cert = base()
|
|
26
|
+
cert.claimLevel = 'verified'
|
|
27
|
+
const result = validateAttestation(cert)
|
|
28
|
+
assert.ok(result.errors.some((e) => /cannot claim verified/.test(e)))
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('attestation: an expired active attestation fails', () => {
|
|
32
|
+
const cert = base()
|
|
33
|
+
cert.status = 'active'
|
|
34
|
+
cert.issuedAt = '2024-01-01'
|
|
35
|
+
cert.expiresAt = '2025-01-01'
|
|
36
|
+
const result = validateAttestation(cert)
|
|
37
|
+
assert.ok(result.errors.some((e) => /cannot be active/.test(e)))
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('attestation: excluded scope is required', () => {
|
|
41
|
+
const cert = base()
|
|
42
|
+
cert.scope.excluded = []
|
|
43
|
+
const result = validateAttestation(cert)
|
|
44
|
+
assert.ok(result.errors.some((e) => /scope\.excluded/.test(e)))
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('attestation: evidence needs a URL or hash', () => {
|
|
48
|
+
const cert = base()
|
|
49
|
+
cert.evidence[0] = { id: 'A', result: 'PASS' }
|
|
50
|
+
const result = validateAttestation(cert)
|
|
51
|
+
assert.ok(result.errors.some((e) => /needs a url or sha256/.test(e)))
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('attestation: disclaimer must deny official/certification', () => {
|
|
55
|
+
const cert = base()
|
|
56
|
+
cert.disclaimer = 'A great plugin, approved.'
|
|
57
|
+
const result = validateAttestation(cert)
|
|
58
|
+
assert.ok(result.errors.some((e) => /non-official/.test(e)))
|
|
59
|
+
})
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { runManifestChecks } from '../src/manifest.mjs'
|
|
6
|
+
import { checkCapabilities, checkCredentials, checkLabels } from '../src/declarations.mjs'
|
|
7
|
+
import { readSources } from '../src/util.mjs'
|
|
8
|
+
import { buildReport } from '../src/report.mjs'
|
|
9
|
+
import { parseInstallSpec } from '../src/install-spec.mjs'
|
|
10
|
+
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url))
|
|
12
|
+
const good = path.join(here, '..', 'fixtures', 'good')
|
|
13
|
+
const bad = path.join(here, '..', 'fixtures', 'bad')
|
|
14
|
+
|
|
15
|
+
test('good fixture passes manifest and version checks', () => {
|
|
16
|
+
const result = runManifestChecks(good)
|
|
17
|
+
assert.equal(result.kind, 'plugin')
|
|
18
|
+
assert.equal(result.checks[0].id, 'DSC-01')
|
|
19
|
+
assert.equal(result.checks[0].result, 'PASS')
|
|
20
|
+
assert.equal(result.checks[1].result, 'PASS')
|
|
21
|
+
assert.equal(result.checks[2].result, 'NA')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('bad fixture fails version and warns licence', () => {
|
|
25
|
+
const result = runManifestChecks(bad)
|
|
26
|
+
assert.equal(result.checks[0].result, 'WARN')
|
|
27
|
+
assert.equal(result.checks[1].result, 'FAIL')
|
|
28
|
+
assert.match(result.checks[1].reason, /engines\.dsh|peer/)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('good fixture declarations are consistent', () => {
|
|
32
|
+
const result = runManifestChecks(good)
|
|
33
|
+
const sources = readSources(good)
|
|
34
|
+
const caps = checkCapabilities(result.manifest, sources, result.patch)
|
|
35
|
+
const creds = checkCredentials(result.manifest, sources)
|
|
36
|
+
const labels = checkLabels(result.manifest, sources)
|
|
37
|
+
assert.equal(caps.result, 'PASS', caps.reason)
|
|
38
|
+
assert.equal(creds.result, 'PASS', creds.reason)
|
|
39
|
+
assert.equal(labels.result, 'PASS', labels.reason)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('bad fixture rejects official label and unknown capability', () => {
|
|
43
|
+
const result = runManifestChecks(bad)
|
|
44
|
+
const sources = readSources(bad)
|
|
45
|
+
const caps = checkCapabilities(result.manifest, sources, result.patch)
|
|
46
|
+
const labels = checkLabels(result.manifest, sources)
|
|
47
|
+
assert.equal(labels.result, 'FAIL')
|
|
48
|
+
assert.match(labels.reason, /official|forbidden/)
|
|
49
|
+
assert.equal(caps.result, 'WARN')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('parseInstallSpec pins git and rejects floating git', () => {
|
|
53
|
+
const pinned = parseInstallSpec('github:acme/dsh-greet#0123456789abcdef0123456789abcdef01234567')
|
|
54
|
+
assert.equal(pinned.kind, 'git')
|
|
55
|
+
assert.equal(pinned.pinned, true)
|
|
56
|
+
assert.throws(() => parseInstallSpec('github:acme/dsh-greet'), /pin/)
|
|
57
|
+
assert.equal(parseInstallSpec('@acme/dsh-greet@1.2.3').pinned, true)
|
|
58
|
+
assert.equal(parseInstallSpec('@acme/dsh-greet').pinned, false)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('report marks missing mandatory checks as incomplete', () => {
|
|
62
|
+
const checks = [
|
|
63
|
+
{ id: 'DSC-01', clause: 'C-1', layer: 'L0', result: 'PASS', coverage: 'full', reason: '', details: [], evidence: [] },
|
|
64
|
+
{ id: 'DSC-02', clause: 'C-2', layer: 'L0', result: 'PASS', coverage: 'full', reason: '', details: [], evidence: [] },
|
|
65
|
+
]
|
|
66
|
+
const report = buildReport({
|
|
67
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
68
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
69
|
+
checks,
|
|
70
|
+
scope: 'ds-c',
|
|
71
|
+
profile: 'package',
|
|
72
|
+
kind: 'plugin',
|
|
73
|
+
})
|
|
74
|
+
assert.equal(report.conclusion.status, 'incomplete')
|
|
75
|
+
assert.equal(report.conclusion.exitCode, 2)
|
|
76
|
+
assert.equal(report.conclusion.level, null)
|
|
77
|
+
assert.ok(report.coverage.notRun > 0)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('report passes when all mandatory checks are full and clean', () => {
|
|
81
|
+
const checks = ['DSC-01', 'DSC-02', 'DSC-04', 'DSC-05', 'DSC-06', 'DSC-07', 'DSC-08', 'DSC-09', 'DSC-11', 'DSC-12', 'DSC-13']
|
|
82
|
+
.map(id => ({ id, clause: id.replace('DSC', 'C'), layer: 'L0', result: 'PASS', coverage: 'full', reason: '', details: [], evidence: [] }))
|
|
83
|
+
const report = buildReport({
|
|
84
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
85
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
86
|
+
checks,
|
|
87
|
+
scope: 'ds-c',
|
|
88
|
+
profile: 'package',
|
|
89
|
+
kind: 'plugin',
|
|
90
|
+
})
|
|
91
|
+
assert.equal(report.conclusion.status, 'pass')
|
|
92
|
+
assert.equal(report.conclusion.exitCode, 0)
|
|
93
|
+
assert.equal(report.conclusion.level, 'DS-C (package)')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test('static-only M1 report maps L1-L3 to NA and issues DS-C static', () => {
|
|
97
|
+
const checks = ['DSC-01', 'DSC-02', 'DSC-03', 'DSC-11', 'DSC-12', 'DSC-13']
|
|
98
|
+
.map(id => ({ id, clause: id.replace('DSC', 'C'), layer: 'L0', result: 'PASS', coverage: 'full', reason: '', details: [], evidence: [] }))
|
|
99
|
+
.concat(['DSC-04', 'DSC-05', 'DSC-06', 'DSC-07', 'DSC-08', 'DSC-09'].map(id => ({ id, clause: id.replace('DSC', 'C'), layer: 'L1', result: 'ERROR', coverage: 'not-run', reason: 'no runtime', details: [], evidence: [] })))
|
|
100
|
+
const report = buildReport({
|
|
101
|
+
subject: { mode: 'listing', profile: 'listing', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
102
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
103
|
+
checks,
|
|
104
|
+
scope: 'ds-c',
|
|
105
|
+
profile: 'listing',
|
|
106
|
+
kind: 'plugin',
|
|
107
|
+
staticOnly: true,
|
|
108
|
+
})
|
|
109
|
+
assert.equal(report.conclusion.status, 'pass')
|
|
110
|
+
assert.equal(report.conclusion.level, 'DS-C static')
|
|
111
|
+
assert.equal(report.conclusion.staticOnly, true)
|
|
112
|
+
assert.equal(report.checks.find(item => item.id === 'DSC-04').result, 'NA')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
function entryChecks(overrides = {}) {
|
|
116
|
+
const make = (id, clause, result = 'PASS', details = []) => ({ id, clause, layer: 'L0', result, coverage: result === 'ERROR' ? 'not-run' : 'full', reason: '', details, evidence: [] })
|
|
117
|
+
return [
|
|
118
|
+
make('DSC-01', 'C-1'),
|
|
119
|
+
make('DSC-02', 'C-2', overrides.c2Result ?? 'PASS', overrides.c2Details ?? []),
|
|
120
|
+
make('DSC-11', 'C-11'),
|
|
121
|
+
make('DSC-12', 'C-12'),
|
|
122
|
+
make('DSC-13', 'C-13'),
|
|
123
|
+
make('DSC-14', 'C-14', overrides.runResult ?? 'PASS'),
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
test('entry: C-2.1 only is WARN, runtime level', () => {
|
|
128
|
+
const report = buildReport({
|
|
129
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
130
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
131
|
+
checks: entryChecks({ c2Result: 'FAIL', c2Details: [{ item: 'C-2.1', result: 'FAIL', reason: 'no engines' }] }),
|
|
132
|
+
scope: 'entry', profile: 'package', kind: 'plugin',
|
|
133
|
+
})
|
|
134
|
+
assert.equal(report.conclusion.status, 'warn')
|
|
135
|
+
assert.equal(report.conclusion.level, 'DSH-ENTRY runtime (warnings)')
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('entry: C-2.2 remains blocking', () => {
|
|
139
|
+
const report = buildReport({
|
|
140
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
141
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
142
|
+
checks: entryChecks({ c2Result: 'FAIL', c2Details: [{ item: 'C-2.2', result: 'FAIL', reason: 'peer mismatch' }] }),
|
|
143
|
+
scope: 'entry', profile: 'package', kind: 'plugin',
|
|
144
|
+
})
|
|
145
|
+
assert.equal(report.conclusion.status, 'fail')
|
|
146
|
+
assert.ok(report.coverage.entryBlocking.failed.includes('C-2.2'))
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('entry: no runtime is incomplete, not static pass', () => {
|
|
150
|
+
const report = buildReport({
|
|
151
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
152
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
153
|
+
checks: entryChecks({ runResult: 'ERROR' }),
|
|
154
|
+
scope: 'entry', profile: 'package', kind: 'plugin',
|
|
155
|
+
})
|
|
156
|
+
assert.equal(report.conclusion.status, 'incomplete')
|
|
157
|
+
assert.equal(report.conclusion.exitCode, 2)
|
|
158
|
+
assert.equal(report.conclusion.level, null)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('entry: static claim recognizes without runtime', () => {
|
|
162
|
+
const checks = entryChecks().filter(c => c.id !== 'DSC-14')
|
|
163
|
+
const report = buildReport({
|
|
164
|
+
subject: { mode: 'package', profile: 'package', kind: 'plugin', kindInferred: false, name: 'x', version: '1.0.0', path: here },
|
|
165
|
+
anchor: { repo: 'x', commit: '0'.repeat(40), scanner: 'x', dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1', runtime: null },
|
|
166
|
+
checks,
|
|
167
|
+
scope: 'entry', profile: 'package', kind: 'plugin', entryClaim: 'static',
|
|
168
|
+
})
|
|
169
|
+
assert.equal(report.conclusion.status, 'pass')
|
|
170
|
+
assert.equal(report.conclusion.level, 'DSH-ENTRY recognized')
|
|
171
|
+
assert.equal(report.conclusion.exitCode, 0)
|
|
172
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { scanText } from '../scripts/claim-check.mjs'
|
|
4
|
+
|
|
5
|
+
test('claim: an official claim fails', () => {
|
|
6
|
+
const r = scanText('DSH-ENTRY is an official certification.', 'x.md')
|
|
7
|
+
assert.equal(r.errors.length, 1)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('claim: a negated claim passes', () => {
|
|
11
|
+
const r = scanText('DSH-ENTRY is not an official certification.', 'x.md')
|
|
12
|
+
assert.deepEqual(r.errors, [])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('claim: Chinese negation passes', () => {
|
|
16
|
+
const r = scanText('DSH-ENTRY 不是官方认证,也不做安全审计。', 'x.md')
|
|
17
|
+
assert.deepEqual(r.errors, [])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('claim: a mark without a disclaimer warns', () => {
|
|
21
|
+
const r = scanText('DSH-FLOW manual', 'x.md')
|
|
22
|
+
assert.equal(r.warnings.length, 1)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('claim: a mark with a disclaimer does not warn', () => {
|
|
26
|
+
const r = scanText('DSH-FLOW manual\n非官方 · 非认证 · 非安全审计', 'x.md')
|
|
27
|
+
assert.deepEqual(r.warnings, [])
|
|
28
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { runManifestChecks } from '../src/manifest.mjs'
|
|
7
|
+
|
|
8
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const ROOT = path.resolve(HERE, '..')
|
|
10
|
+
|
|
11
|
+
test('G4: no dsh.client is not-applicable, not failed', () => {
|
|
12
|
+
const { g4 } = runManifestChecks(path.join(ROOT, 'fixtures/good'))
|
|
13
|
+
assert.equal(g4.hasClient, false)
|
|
14
|
+
assert.equal(g4.ok, true)
|
|
15
|
+
assert.equal(g4.result, 'NA')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('G4: dsh.client without exports["./client"] fails statically', () => {
|
|
19
|
+
const { g4 } = runManifestChecks(path.join(ROOT, 'fixtures/client-missing'))
|
|
20
|
+
assert.equal(g4.hasClient, true)
|
|
21
|
+
assert.equal(g4.ok, false)
|
|
22
|
+
assert.equal(g4.result, 'FAIL')
|
|
23
|
+
assert.match(g4.reason, /exports\["\.\/client"\]/)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('G4: a client package with the export passes statically', () => {
|
|
27
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, 'fixtures/client-missing/package.json'), 'utf8'))
|
|
28
|
+
manifest.exports['./client'] = './client.js'
|
|
29
|
+
const dir = fs.mkdtempSync(path.join(ROOT, 'fixtures', 'client-ok-'))
|
|
30
|
+
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(manifest))
|
|
31
|
+
const { g4 } = runManifestChecks(dir)
|
|
32
|
+
assert.equal(g4.ok, true)
|
|
33
|
+
assert.equal(g4.result, 'PASS')
|
|
34
|
+
fs.rmSync(dir, { recursive: true, force: true })
|
|
35
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import test from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { parseLog, checkCommit, checkTerms } from '../scripts/dco-check.mjs'
|
|
4
|
+
|
|
5
|
+
function commit(body, email = 'a@example.com') {
|
|
6
|
+
return { sha: 'abcdef1234567890', authorName: 'Alice', authorEmail: email, body }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
test('dco: a signed commit passes', () => {
|
|
10
|
+
const r = checkCommit(commit('feat: x\n\nSigned-off-by: Alice <a@example.com>'))
|
|
11
|
+
assert.deepEqual(r.errors, [])
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('dco: missing sign-off fails', () => {
|
|
15
|
+
const r = checkCommit(commit('feat: x'))
|
|
16
|
+
assert.ok(r.errors.some((e) => /missing Signed-off-by/.test(e)))
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('dco: author email must be among sign-offs', () => {
|
|
20
|
+
const r = checkCommit(commit('feat: x\n\nSigned-off-by: Alice <other@example.com>'))
|
|
21
|
+
assert.ok(r.errors.some((e) => /not among the sign-offs/.test(e)))
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('dco: AI-assisted requires a tool and a human sign-off', () => {
|
|
25
|
+
const r = checkCommit(commit('feat: x\n\nAI-Assisted: yes\nSigned-off-by: [bot] <bot@example.com>'))
|
|
26
|
+
assert.ok(r.errors.some((e) => /AI-Tool/.test(e)))
|
|
27
|
+
assert.ok(r.errors.some((e) => /human sign-off/.test(e)))
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('dco: terms checkbox counts', () => {
|
|
31
|
+
const r = checkTerms({
|
|
32
|
+
commits: [{ body: 'feat: x' }],
|
|
33
|
+
prBody: '- [x] I agree to the DSH Contribution Terms v1 (dsh-ct/1)',
|
|
34
|
+
requireTerms: true,
|
|
35
|
+
})
|
|
36
|
+
assert.deepEqual(r.errors, [])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('dco: missing terms fails only when required', () => {
|
|
40
|
+
const r = checkTerms({ commits: [{ body: 'feat: x' }], prBody: '', requireTerms: true })
|
|
41
|
+
assert.ok(r.errors.length === 1)
|
|
42
|
+
assert.deepEqual(checkTerms({ commits: [{ body: 'feat: x' }], prBody: '', requireTerms: false }).errors, [])
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('dco: parseLog keeps author and body', () => {
|
|
46
|
+
const raw = 'abc\x1fAlice\x1fa@example.com\x1ffeat: x\n\nSigned-off-by: Alice <a@example.com>\x1e'
|
|
47
|
+
const [c] = parseLog(raw)
|
|
48
|
+
assert.equal(c.sha, 'abc')
|
|
49
|
+
assert.equal(c.authorEmail, 'a@example.com')
|
|
50
|
+
assert.match(c.body, /Signed-off-by/)
|
|
51
|
+
})
|