dsh-standards 0.0.2 → 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 +17 -4
- 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 -18
- 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
- package/index.mjs +0 -3
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* attestation-check.mjs — validate DSH attestation JSON.
|
|
4
|
+
*
|
|
5
|
+
* The attestation is a quality-grade document (A-E evidence, A-D grade). It is
|
|
6
|
+
* orthogonal to the adoption levels: a `level` field is a hard error.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node 40-checker/scripts/attestation-check.mjs --dir publish/attestations
|
|
10
|
+
* node 40-checker/scripts/attestation-check.mjs --file path/to/cert.json --json
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs'
|
|
13
|
+
import path from 'node:path'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
|
|
16
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
17
|
+
const DEFAULT_ROOT = path.resolve(HERE, '..', '..')
|
|
18
|
+
const STATUS = new Set(['draft', 'active', 'suspended', 'withdrawn', 'expired'])
|
|
19
|
+
const GRADES = new Set(['A', 'B', 'C', 'D'])
|
|
20
|
+
const DIMENSIONS = new Set(['A', 'B', 'C', 'D', 'E'])
|
|
21
|
+
|
|
22
|
+
function date(value) {
|
|
23
|
+
return typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value) && !Number.isNaN(Date.parse(value))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function validateAttestation(cert) {
|
|
27
|
+
const errors = []
|
|
28
|
+
const warn = (m) => errors.push(`WARN ${m}`)
|
|
29
|
+
const err = (m) => errors.push(m)
|
|
30
|
+
if (!cert || typeof cert !== 'object') return { errors: ['attestation must be an object'] }
|
|
31
|
+
if (cert.schema !== 'dsh-attestation/1') err('schema must be dsh-attestation/1')
|
|
32
|
+
if ('level' in cert) err('attestation must not contain a level field (A-D is orthogonal to ENTRY/FLOW/BOOST)')
|
|
33
|
+
if (!/^DSH-ATT-\d{4}-\d{3}$/.test(cert.attestationId || '')) err('attestationId must match DSH-ATT-YYYY-NNN')
|
|
34
|
+
if (!cert.subject || !cert.subject.repo || !cert.subject.version) err('subject.repo and subject.version are required')
|
|
35
|
+
if (!GRADES.has(cert.grade)) err('grade must be A, B, C, or D')
|
|
36
|
+
if (!['self-reported', 'verified', 'peer-reviewed'].includes(cert.claimLevel)) {
|
|
37
|
+
err('claimLevel must be self-reported, verified, or peer-reviewed')
|
|
38
|
+
}
|
|
39
|
+
if (cert.selfAssessed === true && cert.claimLevel !== 'self-reported') {
|
|
40
|
+
err('a self-assessed record cannot claim verified or peer-reviewed')
|
|
41
|
+
}
|
|
42
|
+
if (!STATUS.has(cert.status)) err('status must be draft|active|suspended|withdrawn|expired')
|
|
43
|
+
if (!date(cert.issuedAt)) err('issuedAt must be YYYY-MM-DD')
|
|
44
|
+
if (!date(cert.expiresAt)) err('expiresAt must be YYYY-MM-DD')
|
|
45
|
+
if (date(cert.issuedAt) && date(cert.expiresAt) && Date.parse(cert.expiresAt) <= Date.parse(cert.issuedAt)) {
|
|
46
|
+
err('expiresAt must be after issuedAt')
|
|
47
|
+
}
|
|
48
|
+
if (date(cert.expiresAt) && Date.parse(cert.expiresAt) < Date.now() && cert.status === 'active') {
|
|
49
|
+
err('an expired attestation cannot be active; set status=expired')
|
|
50
|
+
}
|
|
51
|
+
if (!cert.scope || !Array.isArray(cert.scope.dimensions) || cert.scope.dimensions.length === 0) {
|
|
52
|
+
err('scope.dimensions must list A-E')
|
|
53
|
+
} else {
|
|
54
|
+
for (const dimension of cert.scope.dimensions) if (!DIMENSIONS.has(dimension)) err(`invalid scope dimension ${dimension}`)
|
|
55
|
+
}
|
|
56
|
+
if (!Array.isArray(cert.scope?.excluded) || cert.scope.excluded.length === 0) {
|
|
57
|
+
err('scope.excluded must state what the attestation does NOT cover')
|
|
58
|
+
}
|
|
59
|
+
if (!cert.scheme || cert.scheme.id !== 'dsh-certification' || !cert.scheme.version) err('scheme.id/version required')
|
|
60
|
+
if (!cert.assessor || !cert.assessor.handle) err('assessor.handle required')
|
|
61
|
+
if (cert.assessor && !['organizer', 'maintainer', 'reviewer', 'external-reviewer'].includes(cert.assessor.role)) {
|
|
62
|
+
err('assessor.role is invalid')
|
|
63
|
+
}
|
|
64
|
+
if (cert.assessor && !Array.isArray(cert.assessor.coi)) err('assessor.coi must be an array')
|
|
65
|
+
if (typeof cert.selfAssessed !== 'boolean') err('selfAssessed must be boolean')
|
|
66
|
+
if (cert.selfAssessed === true && !(cert.assessor?.coi || []).some((s) => /self|author|own/i.test(s))) {
|
|
67
|
+
warn('selfAssessed is true but assessor.coi does not mention the self/author conflict')
|
|
68
|
+
}
|
|
69
|
+
if (typeof cert.disclaimer !== 'string' || cert.disclaimer.length < 12) err('disclaimer must be a real sentence')
|
|
70
|
+
else if (!/非官方|not official|非认证|not a certification/i.test(cert.disclaimer)) {
|
|
71
|
+
err('disclaimer must say non-official and/or not a certification')
|
|
72
|
+
}
|
|
73
|
+
if (!/^https:\/\//.test(cert.verifyUrl || '')) err('verifyUrl must be https')
|
|
74
|
+
if (!Array.isArray(cert.evidence) || cert.evidence.length === 0) err('evidence must not be empty')
|
|
75
|
+
const ids = new Set()
|
|
76
|
+
for (const item of cert.evidence || []) {
|
|
77
|
+
if (!DIMENSIONS.has(item.id)) err(`evidence id ${item.id} must be A-E`)
|
|
78
|
+
if (ids.has(item.id)) err(`duplicate evidence id ${item.id}`)
|
|
79
|
+
ids.add(item.id)
|
|
80
|
+
if (!['PASS', 'FAIL', 'WARN', 'NOT-RUN'].includes(item.result)) err(`evidence ${item.id} result is invalid`)
|
|
81
|
+
if (!item.url && !item.sha256) err(`evidence ${item.id} needs a url or sha256`)
|
|
82
|
+
if (item.url && !/^https:\/\//.test(item.url)) err(`evidence ${item.id} url must be https`)
|
|
83
|
+
}
|
|
84
|
+
for (const item of cert.evidence || []) {
|
|
85
|
+
if (item.result === 'PASS' && !item.url && !item.sha256) err(`evidence ${item.id} cannot PASS without an artifact`)
|
|
86
|
+
}
|
|
87
|
+
return { errors: errors.filter((e) => !e.startsWith('WARN ')), warnings: errors.filter((e) => e.startsWith('WARN ')).map((e) => e.slice(5)) }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function main(argv = process.argv.slice(2)) {
|
|
91
|
+
let root = DEFAULT_ROOT
|
|
92
|
+
let dir = 'publish/attestations'
|
|
93
|
+
let file = null
|
|
94
|
+
let json = false
|
|
95
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
96
|
+
const arg = argv[i]
|
|
97
|
+
if (arg === '--root') root = path.resolve(argv[++i])
|
|
98
|
+
else if (arg === '--dir') dir = argv[++i]
|
|
99
|
+
else if (arg === '--file') file = path.resolve(argv[++i])
|
|
100
|
+
else if (arg === '--json') json = true
|
|
101
|
+
else if (arg === '--help' || arg === '-h') {
|
|
102
|
+
console.log('usage: attestation-check.mjs [--root <dir>] [--dir <dir>] [--file <json>] [--json]')
|
|
103
|
+
return 0
|
|
104
|
+
} else {
|
|
105
|
+
console.error(`unknown argument: ${arg}`)
|
|
106
|
+
return 2
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
let files = []
|
|
110
|
+
if (file) files = [file]
|
|
111
|
+
else {
|
|
112
|
+
const full = path.join(root, dir)
|
|
113
|
+
if (!fs.existsSync(full)) {
|
|
114
|
+
console.error(`attestation-check: directory not found: ${full}`)
|
|
115
|
+
return 2
|
|
116
|
+
}
|
|
117
|
+
files = fs.readdirSync(full).filter((name) => name.endsWith('.json') && name !== 'index.json').map((name) => path.join(full, name)).sort()
|
|
118
|
+
}
|
|
119
|
+
if (files.length === 0) {
|
|
120
|
+
console.error('attestation-check: no attestation JSON found')
|
|
121
|
+
return 2
|
|
122
|
+
}
|
|
123
|
+
const results = []
|
|
124
|
+
let failed = 0
|
|
125
|
+
for (const item of files) {
|
|
126
|
+
try {
|
|
127
|
+
const cert = JSON.parse(fs.readFileSync(item, 'utf8'))
|
|
128
|
+
const result = validateAttestation(cert)
|
|
129
|
+
if (result.errors.length > 0) failed += 1
|
|
130
|
+
results.push({ file: path.relative(root, item), attestationId: cert.attestationId, ...result })
|
|
131
|
+
} catch (error) {
|
|
132
|
+
failed += 1
|
|
133
|
+
results.push({ file: path.relative(root, item), errors: [`parse error: ${error.message}`], warnings: [] })
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (json) {
|
|
137
|
+
console.log(JSON.stringify({ ok: failed === 0, results }, null, 2))
|
|
138
|
+
} else {
|
|
139
|
+
for (const result of results) {
|
|
140
|
+
for (const warning of result.warnings) console.log(`WARN ${result.file}: ${warning}`)
|
|
141
|
+
for (const error of result.errors) console.log(`FAIL ${result.file}: ${error}`)
|
|
142
|
+
console.log(`${result.errors.length === 0 ? 'PASS' : 'FAIL'} ${result.file}`)
|
|
143
|
+
}
|
|
144
|
+
console.log(`${failed === 0 ? 'PASS' : 'FAIL'} attestation: ${results.length} file(s), ${failed} failed`)
|
|
145
|
+
}
|
|
146
|
+
return failed === 0 ? 0 : 2
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
150
|
+
process.exitCode = main()
|
|
151
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Minimal host-backed bundle smoke: G0 patch parse, G1 compose/row ids,
|
|
4
|
+
* G3 real boot target rows. G2 compatibility is reported from the host API.
|
|
5
|
+
*
|
|
6
|
+
* The checker stays zero-dependency: this script is only used when --host
|
|
7
|
+
* points at a built @deepseek-ai/dsh-app-boot/lib/index.js.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/bundle-smoke.mjs --package <dir> --host <app-boot/lib/index.js> \
|
|
11
|
+
* [--base <base/cordis.patch.yml>] [--json] [--timeout 30000]
|
|
12
|
+
*/
|
|
13
|
+
import fs from 'node:fs'
|
|
14
|
+
import os from 'node:os'
|
|
15
|
+
import path from 'node:path'
|
|
16
|
+
import { pathToFileURL } from 'node:url'
|
|
17
|
+
|
|
18
|
+
function parse(argv) {
|
|
19
|
+
const options = { package: null, host: null, base: null, web: null, bare: null, json: false, timeout: 30_000 }
|
|
20
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
21
|
+
const arg = argv[i]
|
|
22
|
+
if (arg === '--package') options.package = argv[++i]
|
|
23
|
+
else if (arg === '--host') options.host = argv[++i]
|
|
24
|
+
else if (arg === '--base') options.base = argv[++i]
|
|
25
|
+
else if (arg === '--web') options.web = argv[++i]
|
|
26
|
+
else if (arg === '--bare') options.bare = argv[++i]
|
|
27
|
+
else if (arg === '--json') options.json = true
|
|
28
|
+
else if (arg === '--timeout') options.timeout = Number(argv[++i])
|
|
29
|
+
else if (arg === '--help' || arg === '-h') { console.log('usage: node scripts/bundle-smoke.mjs --package <dir> --host <app-boot/lib/index.js> [--base <patch>] [--json]'); process.exit(0) }
|
|
30
|
+
else throw new Error(`unknown option: ${arg}`)
|
|
31
|
+
}
|
|
32
|
+
if (!options.package) throw new Error('--package is required')
|
|
33
|
+
if (!options.host) throw new Error('--host is required')
|
|
34
|
+
if (!Number.isFinite(options.timeout) || options.timeout < 1000) throw new Error('--timeout must be >= 1000')
|
|
35
|
+
return options
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function withTimeout(promise, ms, label) {
|
|
39
|
+
let timer
|
|
40
|
+
const timeout = new Promise((_, reject) => { timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms); timer.unref?.() })
|
|
41
|
+
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function main() {
|
|
45
|
+
const options = parse(process.argv.slice(2))
|
|
46
|
+
const pkg = path.resolve(options.package)
|
|
47
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8'))
|
|
48
|
+
const host = await import(pathToFileURL(path.resolve(options.host)).href)
|
|
49
|
+
const { loadOverlayPatches, composeEntries, boot, getDshRuntimeVersion, evaluatePluginCompatibility } = host
|
|
50
|
+
if (typeof loadOverlayPatches !== 'function' || typeof composeEntries !== 'function' || typeof boot !== 'function') throw new Error('host does not export loadOverlayPatches/composeEntries/boot')
|
|
51
|
+
const bundle = manifest.dsh?.bundle
|
|
52
|
+
if (!bundle?.patch) throw new Error('manifest has no dsh.bundle.patch')
|
|
53
|
+
const files = Array.isArray(bundle.patch) ? bundle.patch : [bundle.patch]
|
|
54
|
+
const patchPaths = files.map(file => path.resolve(pkg, file))
|
|
55
|
+
const targetPatches = patchPaths.flatMap(file => loadOverlayPatches('dsh', file))
|
|
56
|
+
const basePatches = options.base ? loadOverlayPatches('dsh', path.resolve(options.base)) : []
|
|
57
|
+
const webPatches = options.web ? loadOverlayPatches('dsh', path.resolve(options.web)) : []
|
|
58
|
+
const layers = [basePatches, webPatches, targetPatches].filter(layer => layer.length > 0)
|
|
59
|
+
const composed = composeEntries(layers, message => { warnings.push(message) })
|
|
60
|
+
const baseIds = new Set(composeEntries([basePatches, webPatches].filter(layer => layer.length > 0)).filter(row => row.id).map(row => row.id))
|
|
61
|
+
const targetIds = new Set(composed.filter(row => row.id && !baseIds.has(row.id)).map(row => row.id))
|
|
62
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'dsh-bundle-smoke-'))
|
|
63
|
+
const config = path.join(root, 'cordis.yml')
|
|
64
|
+
fs.writeFileSync(config, '[]\n')
|
|
65
|
+
const previousHome = process.env.DSH_HOME
|
|
66
|
+
process.env.DSH_HOME = path.join(root, 'home')
|
|
67
|
+
fs.mkdirSync(process.env.DSH_HOME, { recursive: true })
|
|
68
|
+
let ctx
|
|
69
|
+
let rows = []
|
|
70
|
+
let state = 'failed'
|
|
71
|
+
try {
|
|
72
|
+
const bare = options.bare ? pathToFileURL(path.resolve(options.bare)).href + '/' : pathToFileURL(path.join(root)).href + '/'
|
|
73
|
+
ctx = await withTimeout(boot('bundle-smoke', config, layers.flat(), undefined, bare), options.timeout, 'bundle boot')
|
|
74
|
+
const entries = [...ctx.loader.entries()]
|
|
75
|
+
// A bundle insert is composed under an `include:` group, so the group's
|
|
76
|
+
// fiber can stay null while the inserted plugin row activates. Match the
|
|
77
|
+
// inserted row's package name as well as its id, never only the wrapper.
|
|
78
|
+
const targetNames = new Set(composed
|
|
79
|
+
.filter(row => row.id && !baseIds.has(row.id) && typeof row.name === 'string')
|
|
80
|
+
.map(row => row.name))
|
|
81
|
+
rows = entries.filter(entry => [...targetIds].some(id => entry.id === id || String(entry.id).endsWith(`:${id}`))
|
|
82
|
+
|| targetNames.has(entry.name)).map(entry => ({ id: entry.id, name: entry.name, state: entry.fiber?.state ?? null, disabled: entry.disabled === true }))
|
|
83
|
+
const active = rows.filter(row => row.state === 2 || row.disabled).length
|
|
84
|
+
state = rows.length > 0 && active === rows.length ? 'verified' : rows.length > 0 ? 'partial' : 'failed'
|
|
85
|
+
} finally {
|
|
86
|
+
try { await ctx?.dispose?.() } catch { /* ignore */ }
|
|
87
|
+
if (previousHome === undefined) delete process.env.DSH_HOME
|
|
88
|
+
else process.env.DSH_HOME = previousHome
|
|
89
|
+
fs.rmSync(root, { recursive: true, force: true })
|
|
90
|
+
}
|
|
91
|
+
const compatibility = typeof evaluatePluginCompatibility === 'function' && typeof getDshRuntimeVersion === 'function'
|
|
92
|
+
? (() => { try { return evaluatePluginCompatibility(manifest, {}, getDshRuntimeVersion()) === undefined ? 'admit' : 'reject' } catch { return 'error' } })()
|
|
93
|
+
: 'unknown'
|
|
94
|
+
const hasClient = Boolean(manifest.dsh?.client)
|
|
95
|
+
const clientEntry = manifest.exports?.['./client']
|
|
96
|
+
const clientExport = typeof clientEntry === 'string'
|
|
97
|
+
|| (typeof clientEntry === 'object' && clientEntry !== null && typeof clientEntry.default === 'string')
|
|
98
|
+
// G4 is a composition property: the package's own root row must exist in
|
|
99
|
+
// the composed layer. Runtime `entries` names an `include:` wrapper instead,
|
|
100
|
+
// so reading only activated entries produced false negatives for bundles
|
|
101
|
+
// whose insert is wrapped in an include group.
|
|
102
|
+
const rootRows = composed.filter(row => row.name === manifest.name || row.name === '.' || row.name === './')
|
|
103
|
+
const result = {
|
|
104
|
+
schema: 'dsh-bundle-smoke/1',
|
|
105
|
+
package: manifest.name,
|
|
106
|
+
version: manifest.version,
|
|
107
|
+
g0: { patchFiles: patchPaths.length, parsed: true },
|
|
108
|
+
g1: { rows: composed.length, targetRows: targetIds.size, warnings },
|
|
109
|
+
g2: { compatibility },
|
|
110
|
+
g3: { state, rows, active: rows.filter(row => row.state === 2 || row.disabled).length },
|
|
111
|
+
g4: { hasClient, clientExport, rootRows, ok: !hasClient || (clientExport && rootRows.length > 0) },
|
|
112
|
+
}
|
|
113
|
+
const output = JSON.stringify(result, null, 2)
|
|
114
|
+
const exitCode = state === 'verified' ? 0 : state === 'partial' ? 2 : 1
|
|
115
|
+
// A real boot can leave host-owned timers, sockets, or workers referenced
|
|
116
|
+
// after dispose. This smoke owns the whole process, so terminate once the
|
|
117
|
+
// result is flushed instead of making the caller wait for a handle it cannot
|
|
118
|
+
// see. Without this, a completed boot looks like a timeout to CI.
|
|
119
|
+
process.stdout.write(`${output}\n`, () => process.exit(exitCode))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const warnings = []
|
|
123
|
+
try { await main() } catch (error) {
|
|
124
|
+
console.error(`bundle-smoke: ${error.message}`)
|
|
125
|
+
process.exit(3)
|
|
126
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* claim-check.mjs — conservative scan for mark misuse in public artifacts.
|
|
4
|
+
*
|
|
5
|
+
* It only scans market-facing directories by default (publish/, adoption/) plus
|
|
6
|
+
* README.md. Documentation that *quotes* forbidden words (governance, research
|
|
7
|
+
* notes) is intentionally out of scope.
|
|
8
|
+
*
|
|
9
|
+
* A line fails when it contains a forbidden claim word and no negation, e.g.
|
|
10
|
+
* "DSH-ENTRY official certification" fails, while "not official" passes.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* node 40-checker/scripts/claim-check.mjs [--root <dir>] [--json]
|
|
14
|
+
*/
|
|
15
|
+
import fs from 'node:fs'
|
|
16
|
+
import path from 'node:path'
|
|
17
|
+
import { fileURLToPath } from 'node:url'
|
|
18
|
+
|
|
19
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
20
|
+
const DEFAULT_ROOT = path.resolve(HERE, '..', '..')
|
|
21
|
+
const MARKS = /\bDSH-(?:ENTRY|FLOW|BOOST)\b/i
|
|
22
|
+
const FORBIDDEN = [
|
|
23
|
+
/\bofficial\b/i,
|
|
24
|
+
/\bnational standard\b/i,
|
|
25
|
+
/\bCNAS\b/i,
|
|
26
|
+
/\baccredited\b/i,
|
|
27
|
+
/\bcertified\b/i,
|
|
28
|
+
/\bsecurity audit\b/i,
|
|
29
|
+
/\brecommended\b/i,
|
|
30
|
+
/\branking\b/i,
|
|
31
|
+
/\bguaranteed\b/i,
|
|
32
|
+
/\bapproved by deepseek\b/i,
|
|
33
|
+
/国家标准/,
|
|
34
|
+
/官方认证/,
|
|
35
|
+
/国家认可/,
|
|
36
|
+
/安全审计/,
|
|
37
|
+
/推荐标准/,
|
|
38
|
+
/排名/,
|
|
39
|
+
]
|
|
40
|
+
const NEGATION = /\bnot\b|\bno\b|\bnever\b|\bnon-|\bforbidden\b|\bprohibit|\bdoes not\b|\bcannot\b|非官方|非认证|不是|不得|禁止|不应|不能|不卖|不做|不把|不称|不提供|不收费|不推荐/i
|
|
41
|
+
const SKIP_JSON_KEYS = new Set(['forbiddenWords', 'notClaimed', 'excluded', 'forbidden', 'limitations', 'mustNot', 'cannot'])
|
|
42
|
+
// "official team" is an audience, not a claim about the mark. Strip it before scanning.
|
|
43
|
+
const ALLOWED_CONTEXT = /\bofficial (?:team|adoption|kit|directory|channel)\b|\bofficial\//gi
|
|
44
|
+
const STRONG_CLAIM = /official (?:certification|standard|endorsement)|officially certified|官方认证|国家标准|国家认可/i
|
|
45
|
+
|
|
46
|
+
function walk(dir, out) {
|
|
47
|
+
if (!fs.existsSync(dir)) return
|
|
48
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
49
|
+
const full = path.join(dir, entry.name)
|
|
50
|
+
if (entry.isDirectory()) walk(full, out)
|
|
51
|
+
else if (/\.(md|json|txt)$/.test(entry.name)) out.push(full)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function scanText(text, file) {
|
|
56
|
+
const errors = []
|
|
57
|
+
const warnings = []
|
|
58
|
+
const lines = text.split(/\r?\n/)
|
|
59
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
60
|
+
const line = lines[i]
|
|
61
|
+
const hasMark = MARKS.test(line)
|
|
62
|
+
// Without a mark, only a strong claim ("official certification") fails;
|
|
63
|
+
// a bare "official team" or a path like adoption/official/ is not a claim.
|
|
64
|
+
if (!hasMark && !STRONG_CLAIM.test(line)) continue
|
|
65
|
+
const probe = line.replace(ALLOWED_CONTEXT, ' ')
|
|
66
|
+
if (!hasMark && !FORBIDDEN.some((re) => re.test(probe))) continue
|
|
67
|
+
const context = lines.slice(Math.max(0, i - 2), i + 2).join(' ')
|
|
68
|
+
if (NEGATION.test(probe) || NEGATION.test(context)) continue
|
|
69
|
+
for (const re of FORBIDDEN) {
|
|
70
|
+
if (re.test(probe)) {
|
|
71
|
+
errors.push(`${file}:${i + 1}: forbidden claim "${line.trim().slice(0, 120)}"`)
|
|
72
|
+
break
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (MARKS.test(text) && !/非官方|not official|非认证|not a certification/i.test(text)) {
|
|
77
|
+
warnings.push(`${file}: mark used without a same-page disclaimer`)
|
|
78
|
+
}
|
|
79
|
+
return { errors, warnings }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function collectClaimStrings(value, key, out) {
|
|
83
|
+
if (typeof value === 'string') {
|
|
84
|
+
if (!SKIP_JSON_KEYS.has(key)) out.push(value)
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(value)) {
|
|
88
|
+
for (const item of value) collectClaimStrings(item, key, out)
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
if (value && typeof value === 'object') {
|
|
92
|
+
for (const [childKey, child] of Object.entries(value)) collectClaimStrings(child, childKey, out)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function main(argv = process.argv.slice(2)) {
|
|
97
|
+
let root = DEFAULT_ROOT
|
|
98
|
+
let json = false
|
|
99
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
100
|
+
const arg = argv[i]
|
|
101
|
+
if (arg === '--root') root = path.resolve(argv[++i])
|
|
102
|
+
else if (arg === '--json') json = true
|
|
103
|
+
else if (arg === '--help' || arg === '-h') {
|
|
104
|
+
console.log('usage: claim-check.mjs [--root <dir>] [--json]')
|
|
105
|
+
return 0
|
|
106
|
+
} else {
|
|
107
|
+
console.error(`unknown argument: ${arg}`)
|
|
108
|
+
return 2
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const files = [path.join(root, 'README.md')]
|
|
112
|
+
walk(path.join(root, 'publish'), files)
|
|
113
|
+
walk(path.join(root, 'adoption'), files)
|
|
114
|
+
const results = []
|
|
115
|
+
for (const file of files) {
|
|
116
|
+
if (!fs.existsSync(file)) continue
|
|
117
|
+
if (/mark-policy\.(md|json)$/.test(file)) continue
|
|
118
|
+
let text = fs.readFileSync(file, 'utf8')
|
|
119
|
+
if (file.endsWith('.json')) {
|
|
120
|
+
try {
|
|
121
|
+
const strings = []
|
|
122
|
+
collectClaimStrings(JSON.parse(text), '', strings)
|
|
123
|
+
text = strings.join('\n')
|
|
124
|
+
} catch (error) {
|
|
125
|
+
results.push({ errors: [`${path.relative(root, file)}: parse error: ${error.message}`], warnings: [] })
|
|
126
|
+
continue
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const result = scanText(text, path.relative(root, file))
|
|
130
|
+
if (result.errors.length || result.warnings.length) results.push(result)
|
|
131
|
+
}
|
|
132
|
+
const errors = results.flatMap((r) => r.errors)
|
|
133
|
+
const warnings = results.flatMap((r) => r.warnings)
|
|
134
|
+
if (json) console.log(JSON.stringify({ ok: errors.length === 0, errors, warnings }, null, 2))
|
|
135
|
+
else {
|
|
136
|
+
for (const warning of warnings) console.log(`WARN ${warning}`)
|
|
137
|
+
for (const error of errors) console.log(`FAIL ${error}`)
|
|
138
|
+
console.log(`${errors.length === 0 ? 'PASS' : 'FAIL'} claims: ${errors.length} error(s), ${warnings.length} warning(s)`)
|
|
139
|
+
}
|
|
140
|
+
return errors.length === 0 ? 0 : 2
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
144
|
+
process.exitCode = main()
|
|
145
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* clause-map.mjs — validate the stable clause IDs against spec/levels.json.
|
|
4
|
+
*
|
|
5
|
+
* It checks:
|
|
6
|
+
* - every gate in levels.json is covered by at least one clause;
|
|
7
|
+
* - every clause points to an existing source file;
|
|
8
|
+
* - clause IDs are unique;
|
|
9
|
+
* - no clause maps to a gate that does not exist;
|
|
10
|
+
* - every clause has a level that exists.
|
|
11
|
+
*
|
|
12
|
+
* It does not parse the prose; a human still owns the semantics.
|
|
13
|
+
*
|
|
14
|
+
* Usage: node 40-checker/scripts/clause-map.mjs [--check] [--json]
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import path from 'node:path'
|
|
18
|
+
import { fileURLToPath } from 'node:url'
|
|
19
|
+
|
|
20
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
21
|
+
const ROOT = path.resolve(HERE, '..', '..')
|
|
22
|
+
const LEVELS = path.join(ROOT, 'spec', 'levels.json')
|
|
23
|
+
const CLAUSES = path.join(ROOT, 'spec', 'clauses.json')
|
|
24
|
+
|
|
25
|
+
export function validateClauseMap({ levels, clauses, root = ROOT }) {
|
|
26
|
+
const errors = []
|
|
27
|
+
const warnings = []
|
|
28
|
+
const ids = new Set()
|
|
29
|
+
const knownGates = new Map()
|
|
30
|
+
for (const level of levels.levels || []) {
|
|
31
|
+
knownGates.set(level.id, new Set((level.gates || []).map((gate) => gate.id)))
|
|
32
|
+
}
|
|
33
|
+
const covered = new Map([...knownGates.keys()].map((id) => [id, new Set()]))
|
|
34
|
+
for (const clause of clauses.clauses || []) {
|
|
35
|
+
if (!clause.id) { errors.push('clause without id'); continue }
|
|
36
|
+
if (ids.has(clause.id)) errors.push(`duplicate clause id: ${clause.id}`)
|
|
37
|
+
ids.add(clause.id)
|
|
38
|
+
if (!knownGates.has(clause.level)) {
|
|
39
|
+
errors.push(`${clause.id}: unknown level ${clause.level}`)
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
if (!Array.isArray(clause.gates) || clause.gates.length === 0) {
|
|
43
|
+
errors.push(`${clause.id}: no gates`)
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
for (const gate of clause.gates) {
|
|
47
|
+
if (!knownGates.get(clause.level).has(gate)) {
|
|
48
|
+
errors.push(`${clause.id}: gate ${gate} does not exist in level ${clause.level}`)
|
|
49
|
+
} else {
|
|
50
|
+
covered.get(clause.level).add(gate)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const source = String(clause.source || '').split('#')[0]
|
|
54
|
+
if (!source || !fs.existsSync(path.join(root, source))) {
|
|
55
|
+
errors.push(`${clause.id}: source file not found: ${source}`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const [level, gates] of knownGates) {
|
|
59
|
+
for (const gate of gates) {
|
|
60
|
+
if (!covered.get(level).has(gate)) errors.push(`${level}.${gate}: no clause maps to this gate`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!clauses.normativeCount) warnings.push('clauses.json has no normativeCount; not required')
|
|
64
|
+
return { errors, warnings, covered: Object.fromEntries([...covered].map(([k, v]) => [k, [...v].sort()])) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function main(argv = process.argv.slice(2)) {
|
|
68
|
+
let json = false
|
|
69
|
+
for (const arg of argv) {
|
|
70
|
+
if (arg === '--json') json = true
|
|
71
|
+
else if (arg === '--check') { /* default behaviour */ }
|
|
72
|
+
else if (arg === '--help' || arg === '-h') {
|
|
73
|
+
console.log('usage: clause-map.mjs [--check] [--json]')
|
|
74
|
+
return 0
|
|
75
|
+
} else {
|
|
76
|
+
console.error(`unknown argument: ${arg}`)
|
|
77
|
+
return 2
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const levels = JSON.parse(fs.readFileSync(LEVELS, 'utf8'))
|
|
81
|
+
const clauses = JSON.parse(fs.readFileSync(CLAUSES, 'utf8'))
|
|
82
|
+
const result = validateClauseMap({ levels, clauses })
|
|
83
|
+
if (json) console.log(JSON.stringify(result, null, 2))
|
|
84
|
+
else {
|
|
85
|
+
for (const warning of result.warnings) console.log(`WARN ${warning}`)
|
|
86
|
+
for (const error of result.errors) console.log(`FAIL ${error}`)
|
|
87
|
+
console.log(`${result.errors.length === 0 ? 'PASS' : 'FAIL'} clause map: ${Object.keys(result.covered).map((k) => `${k}=${result.covered[k].length}`).join(' ')}`)
|
|
88
|
+
}
|
|
89
|
+
return result.errors.length === 0 ? 0 : 2
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
93
|
+
process.exitCode = main()
|
|
94
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Collect the known-answer fixture statuses for one runner (OS/Node).
|
|
4
|
+
* Output is the input format of round-robin.mjs.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node 40-checker/scripts/collect-fixtures.mjs --out runner.json
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'node:fs'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import { spawnSync } from 'node:child_process'
|
|
11
|
+
import { fileURLToPath } from 'node:url'
|
|
12
|
+
|
|
13
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
14
|
+
const ROOT = path.resolve(HERE, '..', '..')
|
|
15
|
+
const CHECKER = path.join(ROOT, '40-checker', 'bin', 'dsh-plugin-verify.mjs')
|
|
16
|
+
|
|
17
|
+
function run(dir) {
|
|
18
|
+
const r = spawnSync(process.execPath, [CHECKER, dir, '--scope', 'entry', '--entry-claim', 'static', '--format', 'json'], { encoding: 'utf8', timeout: 120_000, maxBuffer: 8 * 1024 * 1024 })
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(r.stdout)
|
|
21
|
+
return parsed.conclusion?.status ?? 'error'
|
|
22
|
+
} catch {
|
|
23
|
+
return 'error'
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function main() {
|
|
28
|
+
let out = path.join(ROOT, 'runner.json')
|
|
29
|
+
for (let i = 0; i < process.argv.length; i += 1) {
|
|
30
|
+
if (process.argv[i] === '--out') out = path.resolve(process.argv[++i])
|
|
31
|
+
}
|
|
32
|
+
const result = {
|
|
33
|
+
runner: `dsh-plugin-verify@0.1.0 (${process.platform}/${process.arch}, node ${process.version})`,
|
|
34
|
+
anchor: { dsh: '0.2.2-alpha.2', cordis: '4.0.6-alpha.1' },
|
|
35
|
+
results: {
|
|
36
|
+
good: { status: run(path.join(ROOT, '40-checker/fixtures/good')), artifact: 'fixtures/good' },
|
|
37
|
+
'bad-manifest': { status: run(path.join(ROOT, '40-checker/fixtures/bad-manifest')), artifact: 'fixtures/bad-manifest' },
|
|
38
|
+
skipped: { status: 'not-run', artifact: null },
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
fs.writeFileSync(out, `${JSON.stringify(result, null, 2)}\n`)
|
|
42
|
+
console.log(JSON.stringify(result, null, 2))
|
|
43
|
+
}
|
|
44
|
+
main()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* dashboard.mjs — build a small, honest status dashboard from existing results.
|
|
4
|
+
* It never infers a PASS from a missing file.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node 40-checker/scripts/dashboard.mjs [--out dashboard.json]
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'node:fs'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
|
|
12
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
const ROOT = path.resolve(HERE, '..', '..')
|
|
14
|
+
const RESULTS = path.join(ROOT, '40-checker', 'results')
|
|
15
|
+
|
|
16
|
+
function readJson(file) {
|
|
17
|
+
try { return JSON.parse(fs.readFileSync(file, 'utf8')) } catch { return null }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function countFiles(dir, suffix = '.json') {
|
|
21
|
+
if (!fs.existsSync(dir)) return 0
|
|
22
|
+
return fs.readdirSync(dir).filter((name) => name.endsWith(suffix)).length
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildDashboard(root = ROOT) {
|
|
26
|
+
const results = path.join(root, '40-checker', 'results')
|
|
27
|
+
const entryDir = path.join(results, 'entry', '18')
|
|
28
|
+
const entryFiles = fs.existsSync(entryDir)
|
|
29
|
+
? fs.readdirSync(entryDir).filter((name) => name.endsWith('.json') && !name.endsWith('.runtime.json')).length
|
|
30
|
+
: 0
|
|
31
|
+
const flowIndex = readJson(path.join(results, 'flow', 'real', 'index.json'))
|
|
32
|
+
const boost = readJson(path.join(results, 'boost', 'lev12458.json'))
|
|
33
|
+
const attestations = readJson(path.join(root, 'publish', 'attestations', 'index.json'))
|
|
34
|
+
const gov = readJson(path.join(root, 'governance', 'roles.json'))
|
|
35
|
+
const chain = fs.existsSync(path.join(root, 'evidence', 'chain.jsonl'))
|
|
36
|
+
? fs.readFileSync(path.join(root, 'evidence', 'chain.jsonl'), 'utf8').split('\n').filter(Boolean).length
|
|
37
|
+
: 0
|
|
38
|
+
return {
|
|
39
|
+
schema: 'dsh-dashboard/1',
|
|
40
|
+
generatedAt: new Date().toISOString(),
|
|
41
|
+
entry: {
|
|
42
|
+
resultFiles: entryFiles,
|
|
43
|
+
claim: '18/18 recognized static; 10 G3 verified, 8 partial (see results/entry/18/README.md)',
|
|
44
|
+
},
|
|
45
|
+
flow: {
|
|
46
|
+
packages: flowIndex?.samples?.length ?? flowIndex?.results?.length ?? 0,
|
|
47
|
+
summary: flowIndex?.totals ?? flowIndex?.summary ?? null,
|
|
48
|
+
claim: 'J1/J2/J4/J6 runtime on a fixture and 10 real packages; J3/J5/J7/J8 not-run',
|
|
49
|
+
},
|
|
50
|
+
boost: {
|
|
51
|
+
measured: boost?.summary?.measured ?? null,
|
|
52
|
+
measuredCount: boost?.summary?.measured?.length ?? 0,
|
|
53
|
+
claim: 'LEV-1-8 measured at synthetic/loader level; not a production baseline',
|
|
54
|
+
},
|
|
55
|
+
attestations: {
|
|
56
|
+
count: attestations?.attestations?.length ?? 0,
|
|
57
|
+
draft: (attestations?.attestations || []).filter((a) => a.status === 'draft').length,
|
|
58
|
+
selfReported: (attestations?.attestations || []).filter((a) => a.claimLevel === 'self-reported').length,
|
|
59
|
+
},
|
|
60
|
+
governance: {
|
|
61
|
+
schema: gov?.schema ?? null,
|
|
62
|
+
stage: gov?.stage ?? null,
|
|
63
|
+
status: gov?.status ?? null,
|
|
64
|
+
},
|
|
65
|
+
evidenceChainEntries: chain,
|
|
66
|
+
notClaimed: ['official standard', 'certification', 'security audit', 'production readiness', 'ranking'],
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function main(argv = process.argv.slice(2)) {
|
|
71
|
+
let out = path.join(ROOT, 'dashboard.json')
|
|
72
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
73
|
+
if (argv[i] === '--out') out = path.resolve(argv[++i])
|
|
74
|
+
else if (argv[i] === '--help' || argv[i] === '-h') { console.log('usage: dashboard.mjs [--out <file>]'); return 0 }
|
|
75
|
+
else { console.error(`unknown argument: ${argv[i]}`); return 2 }
|
|
76
|
+
}
|
|
77
|
+
const dashboard = buildDashboard(ROOT)
|
|
78
|
+
fs.writeFileSync(out, `${JSON.stringify(dashboard, null, 2)}\n`)
|
|
79
|
+
console.log(JSON.stringify(dashboard, null, 2))
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
84
|
+
process.exitCode = main()
|
|
85
|
+
}
|