@agile-team/wl-skills-gate 0.6.1 → 0.9.1
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/CHANGELOG.md +30 -0
- package/README.md +101 -54
- package/assets/brand-tokens.json +162 -0
- package/assets/wl-bd-logo-dark.svg +29 -0
- package/assets/wl-bd-logo.svg +29 -0
- package/assets/wl-brand-lockup-dark.svg +1 -0
- package/assets/wl-brand-lockup.svg +1 -0
- package/assets/wl-design-logo-dark.svg +29 -0
- package/assets/wl-design-logo.svg +29 -0
- package/assets/wl-gate-logo-dark.svg +29 -0
- package/assets/wl-gate-logo.svg +29 -0
- package/assets/wl-kit-logo-dark.svg +29 -0
- package/assets/wl-kit-logo.svg +29 -0
- package/assets/wl-mark-small.svg +3 -0
- package/assets/wl-mark.svg +3 -0
- package/assets/wl-test-logo-dark.svg +29 -0
- package/assets/wl-test-logo.svg +29 -0
- package/assets/wl-ui-logo-dark.svg +29 -0
- package/assets/wl-ui-logo.svg +29 -0
- package/assets/wl-wordmark-dark.svg +5 -0
- package/assets/wl-wordmark.svg +5 -0
- package/bin/wl-skills-gate.js +180 -8
- package/docs/01-quick-start.md +2 -2
- package/docs/02-config.md +7 -3
- package/docs/05-adapters.md +12 -2
- package/docs/06-gitlab.md +7 -5
- package/docs/09-selftest-coverage.md +4 -2
- package/docs/10-enforcement.md +2 -2
- package/docs/13-quality-cost-and-isolation.md +6 -6
- package/docs/14-low-token-execution.md +8 -8
- package/docs/15-java-report-triage.md +1 -1
- package/docs/16-project-ci-integration.md +64 -0
- package/docs/17-onboarding.md +75 -0
- package/docs/18-ci-source.md +42 -0
- package/docs/19-nine-dimension-review.md +105 -0
- package/docs/README.md +14 -8
- package/fixtures/onboarding/README.md +3 -0
- package/fixtures/onboarding/quality-audit-profile.xml +51 -0
- package/fixtures/onboarding/quality-unit-profile.xml +101 -0
- package/lib/adapters/cmd-json.js +12 -10
- package/lib/adapters/java-xml.js +3 -2
- package/lib/adapters/junit.js +78 -13
- package/lib/adapters/raw-json.js +4 -3
- package/lib/adapters/sarif.js +3 -3
- package/lib/automation.js +247 -0
- package/lib/ci-discovery.js +227 -0
- package/lib/ci-source.js +203 -0
- package/lib/config.js +7 -4
- package/lib/control-deployment.js +44 -0
- package/lib/control-service.js +244 -0
- package/lib/control-store.js +120 -0
- package/lib/deployment-delivery.js +89 -0
- package/lib/deployment-queue.js +101 -0
- package/lib/deployment.js +217 -0
- package/lib/doctor.js +110 -0
- package/lib/evidence.js +59 -7
- package/lib/fix.js +61 -9
- package/lib/governance-notifications.js +45 -0
- package/lib/governance.js +521 -0
- package/lib/identity.js +49 -0
- package/lib/lifecycle-source.js +161 -0
- package/lib/onboard-complete.js +333 -0
- package/lib/onboard-config.js +556 -0
- package/lib/onboard-environment.js +37 -0
- package/lib/onboard-legacy.js +43 -0
- package/lib/onboard-lifecycle.js +117 -0
- package/lib/onboard-registry.js +93 -0
- package/lib/onboard.js +118 -0
- package/lib/promote.js +17 -5
- package/lib/release-set.js +138 -0
- package/lib/report-input.js +22 -8
- package/lib/report-producers.js +37 -19
- package/lib/report-selection.js +136 -0
- package/lib/review-additions.js +159 -0
- package/lib/review-auto.js +75 -0
- package/lib/review-ci.js +119 -0
- package/lib/review-collect.js +146 -0
- package/lib/review-facts.js +160 -0
- package/lib/review-live.js +30 -0
- package/lib/review-publication.js +85 -0
- package/lib/review-publish.js +191 -0
- package/lib/review.js +376 -0
- package/lib/run.js +28 -5
- package/lib/yaml-lite.js +5 -0
- package/package.json +6 -4
- package/schemas/quality-summary.schema.json +22 -0
- package/scripts/lib-tests/automation.test.mjs +126 -0
- package/scripts/lib-tests/ci-discovery.test.mjs +123 -0
- package/scripts/lib-tests/ci-source.test.mjs +153 -0
- package/scripts/lib-tests/control-review.test.mjs +110 -0
- package/scripts/lib-tests/control-service.test.mjs +88 -0
- package/scripts/lib-tests/control-store.test.mjs +77 -0
- package/scripts/lib-tests/deployment-http.test.mjs +66 -0
- package/scripts/lib-tests/deployment.test.mjs +250 -0
- package/scripts/lib-tests/doctor.test.mjs +106 -0
- package/scripts/lib-tests/fix-state.test.mjs +55 -0
- package/scripts/lib-tests/governance-lifecycle.test.mjs +131 -0
- package/scripts/lib-tests/governance.test.mjs +240 -0
- package/scripts/lib-tests/java-unit-wrapper.test.mjs +107 -0
- package/scripts/lib-tests/junit-evidence.test.mjs +214 -0
- package/scripts/lib-tests/lifecycle-source.test.mjs +135 -0
- package/scripts/lib-tests/onboard-complete.test.mjs +324 -0
- package/scripts/lib-tests/onboard-registry.test.mjs +51 -0
- package/scripts/lib-tests/onboard-review-facts.test.mjs +89 -0
- package/scripts/lib-tests/onboard.test.mjs +180 -0
- package/scripts/lib-tests/review-additions.test.mjs +98 -0
- package/scripts/lib-tests/review-auto.test.mjs +94 -0
- package/scripts/lib-tests/review-ci.test.mjs +72 -0
- package/scripts/lib-tests/review-collect.test.mjs +61 -0
- package/scripts/lib-tests/review-facts.test.mjs +44 -0
- package/scripts/lib-tests/review-publication.test.mjs +47 -0
- package/scripts/lib-tests/review-publish.test.mjs +89 -0
- package/scripts/lib-tests/review.test.mjs +212 -0
- package/scripts/lib-tests/yaml-lite.test.mjs +21 -0
- package/scripts/run-integration.mjs +49 -7
- package/scripts/test-support/control-review-fixture.mjs +57 -0
- package/scripts/test-support/review-collect-fixture.mjs +47 -0
- package/templates/ci/Jenkinsfile +58 -0
- package/templates/ci/Jenkinsfile.attest +32 -0
- package/templates/ci/Jenkinsfile.automation +20 -0
- package/templates/ci/Jenkinsfile.deployment +78 -0
- package/templates/ci/Jenkinsfile.release-sign +26 -0
- package/templates/ci/Jenkinsfile.review-sign +30 -0
- package/templates/ci/central-review.sh +10 -0
- package/templates/ci/controlled-deployment-http.mjs +72 -0
- package/templates/ci/create-deployment-facts.mjs +7 -0
- package/templates/ci/deployment-http.json +14 -0
- package/templates/ci/gitlab-backend.yml +40 -0
- package/templates/ci/gitlab-frontend.yml +32 -0
- package/templates/ci/produce-review-facts.mjs +15 -0
- package/templates/ci/publish-reviews.mjs +5 -0
- package/templates/ci/sign-collected-release.mjs +7 -0
- package/templates/ci/wl-quality-automation.service +18 -0
- package/templates/ci/wl-quality-control.service +18 -0
- package/templates/onboarding/automation/ide-tasks.json +31 -0
- package/templates/onboarding/automation/project-actions.mjs +266 -0
- package/templates/onboarding/backend/java-unit.mjs +84 -0
- package/templates/onboarding/backend/java-unit.plan.json +15 -0
- package/templates/onboarding/backend/policy.yml +63 -0
- package/templates/onboarding/backend/quality-tools.package.json +9 -0
- package/templates/onboarding/backend/run.mjs +10 -0
- package/templates/onboarding/frontend/policy.yml +40 -0
- package/templates/onboarding/legacy/backend-commit-msg.sh +21 -0
- package/templates/onboarding/legacy/frontend-common-core-postinstall.mjs +52 -0
- package/templates/onboarding/legacy/frontend-enforce-pnpm.mjs +9 -0
- package/templates/onboarding/legacy/frontend-pre-commit.sh +15 -0
- package/templates/onboarding/legacy/frontend-pre-push.sh +16 -0
- package/templates/platform/README.md +33 -0
- package/templates/platform/action.example.json +15 -0
- package/templates/platform/automation-config.json +66 -0
- package/templates/platform/ci-source.backend.json +40 -0
- package/templates/platform/ci-source.frontend.json +42 -0
- package/templates/platform/ci-source.gitlab.json +18 -0
- package/templates/platform/ci-source.jenkins.json +31 -0
- package/templates/platform/control-config.json +48 -0
- package/templates/platform/deployment-config.json +92 -0
- package/templates/platform/event.example.json +17 -0
- package/templates/platform/expectations.example.json +16 -0
- package/templates/platform/governance-config.json +106 -0
- package/templates/platform/lifecycle-event.example.json +29 -0
- package/templates/platform/review-ci.backend.json +6 -0
- package/templates/platform/review-ci.frontend.json +6 -0
- package/templates/platform/review-collector.backend.json +59 -0
- package/templates/platform/review-collector.frontend.json +67 -0
- package/templates/platform/review-policy.backend.json +72 -0
- package/templates/platform/review-policy.frontend.json +71 -0
- package/templates/platform/review-publish-config.json +45 -0
- package/templates/quality/java-unit.plan.json +13 -0
- package/templates/quality/review-evidence.plan.json +11 -0
- package/templates/quality/review-input.example.json +25 -0
- package/templates/quality/review-policy.json +15 -0
- package/templates/quality/rules.lock.json +1 -1
- package/templates/scripts-quality/java-unit.mjs +83 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-kit</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-kit package, frontend engineering, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#0B1119"/><stop offset="1" stop-color="#111E2C"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#F7FAFA"/><stop offset=".58" stop-color="#B4C3CE"/><stop offset="1" stop-color="#E7EEF2"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#52677C" stop-opacity=".4"/><stop offset="1" stop-color="#52677C" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#9CC5FF" opacity=".035"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="url(#metal)"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#9CC5FF"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#9CAAB8" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#52677C" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#9CC5FF" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#9CC5FF" font-size="12" font-weight="600" letter-spacing="3.5">FRONTEND ENGINEERING</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#9CAAB8" font-weight="350">skills-</tspan><tspan fill="#F0F4F6" font-weight="550">kit</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#8E9FAF" font-size="20" font-weight="400" letter-spacing=".2">Standards · Contracts · Workflows</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#8E9FAF" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-kit</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#9CC5FF" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M20 21H42V43H20ZM54 21H76V43H54ZM20 55H42V77H20ZM65 51 80 66 65 81 50 66Z"/><path d="M54 21H76V28" stroke-width="4"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#52677C" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-kit</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-kit package, frontend engineering, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#F7F8F8"/><stop offset="1" stop-color="#EFF2F4"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#21394D"/><stop offset=".58" stop-color="#0C2031"/><stop offset="1" stop-color="#284156"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#AEBCC6" stop-opacity=".4"/><stop offset="1" stop-color="#AEBCC6" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#315E9F" opacity=".04"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="#172634"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#315E9F"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#687A89" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#AEBCC6" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#315E9F" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#315E9F" font-size="12" font-weight="600" letter-spacing="3.5">FRONTEND ENGINEERING</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#687A89" font-weight="350">skills-</tspan><tspan fill="#172634" font-weight="550">kit</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#637686" font-size="20" font-weight="400" letter-spacing=".2">Standards · Contracts · Workflows</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#637686" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-kit</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#315E9F" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M20 21H42V43H20ZM54 21H76V43H54ZM20 55H42V77H20ZM65 51 80 66 65 81 50 66Z"/><path d="M54 21H76V28" stroke-width="4"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#AEBCC6" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 168" fill="currentColor" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading</title><desc id="desc">Original World Leading monogram. Precision-cut W and forward-cut L. Optically spaced for small use.</desc>
|
|
3
|
+
<path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z" transform="translate(8 0)"/></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 168" fill="currentColor" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading</title><desc id="desc">Original World Leading monogram. Precision-cut W and forward-cut L. Single-color master mark.</desc>
|
|
3
|
+
<path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/></svg>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-test</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-test package, test engineering, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#0B1119"/><stop offset="1" stop-color="#111E2C"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#F7FAFA"/><stop offset=".58" stop-color="#B4C3CE"/><stop offset="1" stop-color="#E7EEF2"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#52677C" stop-opacity=".4"/><stop offset="1" stop-color="#52677C" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#E7A7B8" opacity=".035"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="url(#metal)"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#E7A7B8"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#9CAAB8" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#52677C" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#E7A7B8" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#E7A7B8" font-size="12" font-weight="600" letter-spacing="3.5">TEST ENGINEERING</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#9CAAB8" font-weight="350">skills-</tspan><tspan fill="#F0F4F6" font-weight="550">test</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#8E9FAF" font-size="20" font-weight="400" letter-spacing=".2">Cases · Automation · Evidence</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#8E9FAF" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-test</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#E7A7B8" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M18 21H78V77H18ZM18 39H78M36 39V77M56 39V77"/><path d="M25 49 29 53 34 46M42 65 46 69 52 61M63 49H71M63 65H71"/><path d="M26 29H32" stroke-width="3"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#52677C" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-test</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-test package, test engineering, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#F7F8F8"/><stop offset="1" stop-color="#EFF2F4"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#21394D"/><stop offset=".58" stop-color="#0C2031"/><stop offset="1" stop-color="#284156"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#AEBCC6" stop-opacity=".4"/><stop offset="1" stop-color="#AEBCC6" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#A34262" opacity=".04"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="#172634"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#A34262"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#687A89" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#AEBCC6" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#A34262" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#A34262" font-size="12" font-weight="600" letter-spacing="3.5">TEST ENGINEERING</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#687A89" font-weight="350">skills-</tspan><tspan fill="#172634" font-weight="550">test</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#637686" font-size="20" font-weight="400" letter-spacing=".2">Cases · Automation · Evidence</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#637686" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-test</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#A34262" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M18 21H78V77H18ZM18 39H78M36 39V77M56 39V77"/><path d="M25 49 29 53 34 46M42 65 46 69 52 61M63 49H71M63 65H71"/><path d="M26 29H32" stroke-width="3"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#AEBCC6" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-ui</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-ui package, interface quality, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#0B1119"/><stop offset="1" stop-color="#111E2C"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#F7FAFA"/><stop offset=".58" stop-color="#B4C3CE"/><stop offset="1" stop-color="#E7EEF2"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#52677C" stop-opacity=".4"/><stop offset="1" stop-color="#52677C" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#CCB8FF" opacity=".035"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="url(#metal)"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#CCB8FF"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#9CAAB8" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#52677C" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#CCB8FF" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#CCB8FF" font-size="12" font-weight="600" letter-spacing="3.5">INTERFACE QUALITY</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#9CAAB8" font-weight="350">skills-</tspan><tspan fill="#F0F4F6" font-weight="550">ui</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#8E9FAF" font-size="20" font-weight="400" letter-spacing=".2">Tokens · Layouts · Interaction</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#8E9FAF" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-ui</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#CCB8FF" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M18 24H72L80 32V76H18Z"/><path d="M18 37H80M38 37V76M47 48H69M47 58H61"/><path d="M25 30H30" stroke-width="3"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#52677C" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 340" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">WL · World Leading · skills-ui</title>
|
|
3
|
+
<desc id="desc">World Leading signature on the left. The skills-ui package, interface quality, on the right. Shared precision industrial identity.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="surface" x1="0" y1="0" x2="1280" y2="340" gradientUnits="userSpaceOnUse"><stop stop-color="#F7F8F8"/><stop offset="1" stop-color="#EFF2F4"/></linearGradient>
|
|
6
|
+
<linearGradient id="metal" x1="0" y1="22" x2="200" y2="149" gradientUnits="userSpaceOnUse"><stop stop-color="#21394D"/><stop offset=".58" stop-color="#0C2031"/><stop offset="1" stop-color="#284156"/></linearGradient>
|
|
7
|
+
<linearGradient id="rule" gradientUnits="userSpaceOnUse" x1="400" y1="281" x2="1218" y2="281"><stop stop-color="#AEBCC6" stop-opacity=".4"/><stop offset="1" stop-color="#AEBCC6" stop-opacity=".12"/></linearGradient>
|
|
8
|
+
<clipPath id="canvas"><rect width="1280" height="340" rx="16"/></clipPath>
|
|
9
|
+
</defs>
|
|
10
|
+
<g clip-path="url(#canvas)">
|
|
11
|
+
<rect width="1280" height="340" fill="url(#surface)"/>
|
|
12
|
+
<path d="M1247 0H1280V340H1148Z" fill="#7053A7" opacity=".04"/>
|
|
13
|
+
<g transform="translate(60 58) scale(1.12)" fill="#172634"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/><path d="M174 112H226L218 136H166Z" fill="#7053A7"/></g>
|
|
14
|
+
<text x="195" y="258" text-anchor="middle" fill="#687A89" font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif" font-size="16" font-weight="500" letter-spacing="3.15">WORLD LEADING</text>
|
|
15
|
+
<path d="M352 72V278" stroke="#AEBCC6" stroke-opacity=".35"/>
|
|
16
|
+
<path d="M352 153V192" stroke="#7053A7" stroke-opacity=".85" stroke-width="2"/>
|
|
17
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif">
|
|
18
|
+
<text x="400" y="88" fill="#7053A7" font-size="12" font-weight="600" letter-spacing="3.5">INTERFACE QUALITY</text>
|
|
19
|
+
<text x="393" y="187" font-size="90" letter-spacing="-4"><tspan fill="#687A89" font-weight="350">skills-</tspan><tspan fill="#172634" font-weight="550">ui</tspan></text>
|
|
20
|
+
<text x="400" y="236" fill="#637686" font-size="20" font-weight="400" letter-spacing=".2">Tokens · Layouts · Interaction</text>
|
|
21
|
+
</g>
|
|
22
|
+
<path d="M400 281H1218" stroke="url(#rule)"/>
|
|
23
|
+
<text x="400" y="311" fill="#637686" font-family="'SFMono-Regular', Consolas, 'Liberation Mono', monospace" font-size="13" letter-spacing=".15">@agile-team/wl-skills-ui</text>
|
|
24
|
+
<g transform="translate(1049 83) scale(1.68)" fill="none" stroke="#7053A7" stroke-linecap="square" stroke-linejoin="miter">
|
|
25
|
+
<path d="M8 23V8H23M73 8H88V23M88 73V88H73M23 88H8V73" stroke-width=".8" opacity=".22"/>
|
|
26
|
+
<g stroke-width="2" opacity=".85"><path d="M18 24H72L80 32V76H18Z"/><path d="M18 37H80M38 37V76M47 48H69M47 58H61"/><path d="M25 30H30" stroke-width="3"/></g>
|
|
27
|
+
</g>
|
|
28
|
+
<rect x=".5" y=".5" width="1279" height="339" rx="15.5" fill="none" stroke="#AEBCC6" stroke-opacity=".2"/>
|
|
29
|
+
</g></svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 160" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">World Leading · WL</title><desc id="desc">World Leading master wordmark. The WL monogram and full brand name, independent of any product.</desc>
|
|
3
|
+
<g fill="#EEF1F2" transform="translate(12 10) scale(.87)"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/></g>
|
|
4
|
+
<path d="M250 36V127" fill="none" stroke="#8D9BAA" stroke-opacity=".35"/>
|
|
5
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif"><text x="290" y="82" fill="#EEF1F2" font-size="36" font-weight="500" letter-spacing="2.5">WORLD LEADING</text><text x="293" y="115" fill="#8D9BAA" font-size="11" font-weight="500" letter-spacing="4.8">ENGINEERING</text></g></svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 160" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">World Leading · WL</title><desc id="desc">World Leading master wordmark. The WL monogram and full brand name, independent of any product.</desc>
|
|
3
|
+
<g fill="#172331" transform="translate(12 10) scale(.87)"><path d="M18 24H42L58 84L82 24H104L126 84L145 24H170L134 136H111L93 100L76 136H53Z"/><path d="M181 24H205L174 112H226L218 136H142Z"/></g>
|
|
4
|
+
<path d="M250 36V127" fill="none" stroke="#66717C" stroke-opacity=".35"/>
|
|
5
|
+
<g font-family="'Helvetica Neue', Inter, Helvetica, Arial, sans-serif"><text x="290" y="82" fill="#172331" font-size="36" font-weight="500" letter-spacing="2.5">WORLD LEADING</text><text x="293" y="115" fill="#66717C" font-size="11" font-weight="500" letter-spacing="4.8">ENGINEERING</text></g></svg>
|
package/bin/wl-skills-gate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { mkdirSync, writeFileSync, lstatSync, statSync, realpathSync } from "node:fs";
|
|
4
|
+
import { git } from "../lib/source-state.js";
|
|
4
5
|
import { runGate } from "../lib/run.js";
|
|
5
6
|
import { buildFixPlan, applyFixPlan } from "../lib/fix.js";
|
|
6
7
|
import { verifyArtifact } from "../lib/verify-artifact.js";
|
|
@@ -9,7 +10,7 @@ import { signGateProof, createArtifactManifest, signReviewRecord } from "../lib/
|
|
|
9
10
|
import { validateCommitMessage } from "../lib/commit-message.js";
|
|
10
11
|
|
|
11
12
|
const [command, ...rest] = process.argv.slice(2);
|
|
12
|
-
const FLAGS = new Set(["--confirm", "--push", "--allow-any"]);
|
|
13
|
+
const FLAGS = new Set(["--confirm", "--push", "--allow-any", "--include-digest", "--send", "--watch"]);
|
|
13
14
|
|
|
14
15
|
function options(allowed) {
|
|
15
16
|
const out = { positional: [] };
|
|
@@ -33,6 +34,27 @@ function writeJson(file, value) {
|
|
|
33
34
|
console.log(`[${command}] 已写入 ${file}`);
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
function protectOutput(file, inputs = [], projectRoot) {
|
|
38
|
+
if (!file) return;
|
|
39
|
+
const destination = path.resolve(file); let current = path.parse(destination).root;
|
|
40
|
+
for (const part of destination.slice(current.length).split(path.sep)) {
|
|
41
|
+
current = path.join(current, part); let info;
|
|
42
|
+
try { info = lstatSync(current); } catch (error) { if (error.code !== "ENOENT") throw error; }
|
|
43
|
+
if (info?.isSymbolicLink()) throw new Error("输出路径不能包含符号链接或断链");
|
|
44
|
+
}
|
|
45
|
+
let outputStat; try { outputStat = statSync(destination); } catch (error) { if (error.code !== "ENOENT") throw error; }
|
|
46
|
+
for (const input of inputs.filter(Boolean)) {
|
|
47
|
+
if (path.resolve(input) === destination) throw new Error("输出不能覆盖台账/配置/原输入或密钥");
|
|
48
|
+
if (outputStat) { let inputStat; try { inputStat = statSync(input); } catch (error) { if (error.code !== "ENOENT") throw error; }
|
|
49
|
+
if (inputStat && inputStat.dev === outputStat.dev && inputStat.ino === outputStat.ino) throw new Error("输出不能覆盖原输入的硬链接别名"); }
|
|
50
|
+
}
|
|
51
|
+
if (projectRoot) {
|
|
52
|
+
const root = path.resolve(projectRoot), relative = path.relative(root, destination);
|
|
53
|
+
let tracked = []; try { tracked = git(["ls-files", "-z"], root).split("\0"); } catch {}
|
|
54
|
+
if (tracked.includes(relative)) throw new Error("只读预检输出不能覆盖已跟踪项目文件");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
36
58
|
const PROOF_FLAGS = ["--summary", "--sha", "--project", "--env", "--expect-policy-hash", "--expect-rules-hash",
|
|
37
59
|
"--expect-baseline-hash", "--expect-waivers-hash",
|
|
38
60
|
"--expect-pipeline-id", "--expect-job-id",
|
|
@@ -51,6 +73,142 @@ function proofOptions(o) {
|
|
|
51
73
|
try {
|
|
52
74
|
if (command === "run") {
|
|
53
75
|
process.exitCode = (await runGate({ argv: rest })).exitCode;
|
|
76
|
+
} else if (command === "onboard") {
|
|
77
|
+
const { runOnboardCli } = await import("../lib/onboard.js");
|
|
78
|
+
process.exitCode = await runOnboardCli(rest);
|
|
79
|
+
} else if (command === "doctor") {
|
|
80
|
+
const o = options(["--root", "--kind", "--out"]);
|
|
81
|
+
if (o.positional.length) throw new Error("doctor 不接受位置参数");
|
|
82
|
+
const { doctor } = await import("../lib/doctor.js");
|
|
83
|
+
if (o["--out"]) { const root = path.resolve(o["--root"] || "."), canonicalRoot = realpathSync(root), out = path.resolve(o["--out"]); if ([root, canonicalRoot].some((r) => out === r || out.startsWith(r + path.sep))) throw new Error("doctor 只读项目,--out 必须放在项目外证据目录"); }
|
|
84
|
+
const result = doctor({ root: o["--root"], kind: o["--kind"] });
|
|
85
|
+
protectOutput(o["--out"], [], o["--root"] || ".");
|
|
86
|
+
if (o["--out"]) writeJson(o["--out"], result); else process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
87
|
+
process.exitCode = result.status === "gaps" ? 2 : 0;
|
|
88
|
+
} else if (command === "automation") {
|
|
89
|
+
const o = options(["--config", "--send", "--watch"]);
|
|
90
|
+
if (o.positional.length || !o["--config"]) throw new Error("automation 要求中央 --config;--watch 定时运行;--send 实际投递");
|
|
91
|
+
const { automationTick, startAutomation } = await import("../lib/automation.js");
|
|
92
|
+
if (o["--watch"]) { const loop = startAutomation({ configFile: o["--config"], send: !!o["--send"] }); for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => loop.stop()); }
|
|
93
|
+
else { const result = await automationTick({ configFile: o["--config"], send: !!o["--send"] }); process.stdout.write(JSON.stringify(result, null, 2) + "\n"); process.exitCode = result.status === "ok" ? 0 : 2; }
|
|
94
|
+
} else if (command === "control") {
|
|
95
|
+
const operation = rest.shift();
|
|
96
|
+
const o = options(["--config", "--port", "--review-id", "--record", "--evidence-root", "--provenance", "--plan-id", "--config-id", "--plan", "--release-set"]);
|
|
97
|
+
if (o.positional.length || !o["--config"]) throw new Error("control 要求 --config;子命令 serve/register-review/register-deployment");
|
|
98
|
+
const control = await import("../lib/control-service.js"); let result;
|
|
99
|
+
if (operation === "serve") {
|
|
100
|
+
const server = await control.serveControl({ configFile: o["--config"], port: o["--port"] === undefined ? 8787 : Number(o["--port"]) });
|
|
101
|
+
for (const signal of ["SIGINT", "SIGTERM"]) process.once(signal, () => server.close());
|
|
102
|
+
result = { status: "listening", host: "127.0.0.1", port: server.address().port };
|
|
103
|
+
} else if (operation === "register-review") result = await control.registerControlReview({ configFile: o["--config"], reviewId: o["--review-id"], recordFile: o["--record"], evidenceRoot: o["--evidence-root"], provenanceFile: o["--provenance"] });
|
|
104
|
+
else if (operation === "register-deployment") { const { registerControlDeployment } = await import("../lib/control-deployment.js"); result = await registerControlDeployment({ config: control.loadControlConfig(o["--config"]), planId: o["--plan-id"], configId: o["--config-id"], planFile: o["--plan"], releaseSetFile: o["--release-set"] }); }
|
|
105
|
+
else throw new Error("control 子命令 serve/register-review/register-deployment");
|
|
106
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
107
|
+
} else if (command === "review-facts") {
|
|
108
|
+
const o = options(["--root", "--summary", "--plan", "--out-dir", "--base-sha"]);
|
|
109
|
+
if (o.positional.length) throw new Error("review-facts 不接受位置参数");
|
|
110
|
+
const { produceReviewFacts } = await import("../lib/review-facts.js");
|
|
111
|
+
process.stdout.write(JSON.stringify(produceReviewFacts({ root: o["--root"] || process.cwd(), summaryFile: o["--summary"] || "quality-reports/quality-summary.json", planFile: o["--plan"], outDir: o["--out-dir"] || "quality-reports/review", baseSha: o["--base-sha"] }), null, 2) + "\n");
|
|
112
|
+
} else if (command === "review-publish") {
|
|
113
|
+
const o = options(["--config"]); if (o.positional.length || !o["--config"]) throw new Error("review-publish 要求独立签发作业 --config");
|
|
114
|
+
const { publishReviewAuthorizations } = await import("../lib/review-publish.js"); const result = await publishReviewAuthorizations({ configFile: o["--config"] });
|
|
115
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n"); process.exitCode = result.status === "ok" ? 0 : 2;
|
|
116
|
+
} else if (command === "review-ci") {
|
|
117
|
+
const o = options(["--config", "--source", "--out"]);
|
|
118
|
+
if (o.positional.length || !o["--config"] || !o["--source"] || !o["--out"]) throw new Error("review-ci 要求 --config --source --out 新证据目录");
|
|
119
|
+
const { createCiReview } = await import("../lib/review-ci.js");
|
|
120
|
+
process.stdout.write(JSON.stringify(await createCiReview({ configFile: o["--config"], sourceFile: o["--source"], outDir: o["--out"] }), null, 2) + "\n");
|
|
121
|
+
} else if (command === "review-collect") {
|
|
122
|
+
const o = options(["--config", "--source", "--input", "--record", "--evidence-root", "--out"]);
|
|
123
|
+
if (o.positional.length) throw new Error("review-collect 不接受位置参数");
|
|
124
|
+
for (const flag of ["--config", "--source", "--input", "--record", "--evidence-root", "--out"]) if (!o[flag]) throw new Error(`review-collect 缺少 ${flag}`);
|
|
125
|
+
const { collectReviewEvidence } = await import("../lib/review-collect.js");
|
|
126
|
+
const result = collectReviewEvidence({ configFile: o["--config"], sourceFile: o["--source"], inputFile: o["--input"], recordFile: o["--record"], evidenceRoot: o["--evidence-root"], outDir: o["--out"] });
|
|
127
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
128
|
+
} else if (command === "release-set") {
|
|
129
|
+
const operation = rest.shift(), o = options(["--input", "--evidence-root", "--expect-input-hash", "--private-key", "--issuer", "--out", "--release-set", "--public-key", "--expect-issuer", "--expect-release-set-hash", "--env"]);
|
|
130
|
+
if (o.positional.length) throw new Error("release-set 不接受位置参数");
|
|
131
|
+
const { createReleaseSet, verifyReleaseSet } = await import("../lib/release-set.js"); let result;
|
|
132
|
+
if (operation === "create") { protectOutput(o["--out"], [o["--input"], o["--private-key"]]); result = createReleaseSet({ inputFile: o["--input"], evidenceRoot: o["--evidence-root"], expectInputHash: o["--expect-input-hash"], privateKeyFile: o["--private-key"], issuer: o["--issuer"], outFile: o["--out"] }); }
|
|
133
|
+
else if (operation === "verify") result = verifyReleaseSet({ releaseSetFile: o["--release-set"], publicKeyFile: o["--public-key"], expectIssuer: o["--expect-issuer"], expectReleaseSetHash: o["--expect-release-set-hash"], env: o["--env"] });
|
|
134
|
+
else throw new Error("release-set 子命令 create/verify");
|
|
135
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
136
|
+
} else if (command === "deployment") {
|
|
137
|
+
const operation = rest.shift(), o = options(["--config", "--release-set", "--expect-release-set-hash", "--state", "--action", "--out", "--out-dir", "--plan", "--authorization", "--private-key", "--send", "--execution", "--executor-public-key", "--project", "--sequence", "--pipeline-id", "--job-id", "--pipeline-url", "--report-url", "--requests-dir", "--plan-id", "--config-id", "--authorization-dir", "--timeout-ms", "--delivery-dir"]);
|
|
138
|
+
if (o.positional.length) throw new Error("deployment 不接受位置参数");
|
|
139
|
+
const d = await import("../lib/deployment.js"), base = { configFile: o["--config"], releaseSetFile: o["--release-set"], expectReleaseSetHash: o["--expect-release-set-hash"], stateFile: o["--state"] }; let result;
|
|
140
|
+
if (operation === "plan") { protectOutput(o["--out"], [o["--config"], o["--release-set"], o["--state"]]); result = d.planDeployment({ ...base, action: o["--action"], outFile: o["--out"] }); }
|
|
141
|
+
else if (operation === "queue") { const { queueDeploymentPlan } = await import("../lib/deployment-queue.js"); result = queueDeploymentPlan({ requestsDir: o["--requests-dir"], planId: o["--plan-id"], configId: o["--config-id"], planFile: o["--plan"], releaseSetFile: o["--release-set"] }); }
|
|
142
|
+
else if (operation === "run-authorized") {
|
|
143
|
+
const { waitForDeploymentAuthorization } = await import("../lib/deployment-queue.js");
|
|
144
|
+
if (!o["--authorization-dir"]) throw new Error("run-authorized 要求中央固定 --authorization-dir");
|
|
145
|
+
// A preview never waits for or consumes a human authorization.
|
|
146
|
+
if (!o["--send"]) result = d.runDeployment({ ...base, planFile: o["--plan"], privateKeyFile: o["--private-key"], outDir: o["--out-dir"], send: false });
|
|
147
|
+
else {
|
|
148
|
+
const selected = await waitForDeploymentAuthorization({ configFile: o["--config"], planFile: o["--plan"], authorizationDir: o["--authorization-dir"], timeoutMs: o["--timeout-ms"] === undefined ? 900000 : Number(o["--timeout-ms"]) });
|
|
149
|
+
result = selected.status === "authorized" ? d.runDeployment({ ...base, planFile: o["--plan"], authorizationFile: selected.authorizationFile, privateKeyFile: o["--private-key"], outDir: o["--out-dir"], send: true }) : selected;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (operation === "deliver") { const { queueDeploymentDelivery } = await import("../lib/deployment-queue.js"); result = queueDeploymentDelivery({ deliveryDir: o["--delivery-dir"], configId: o["--config-id"], executionFile: o["--execution"], releaseSetFile: o["--release-set"], expectReleaseSetHash: o["--expect-release-set-hash"] }); }
|
|
153
|
+
else if (operation === "run") result = d.runDeployment({ ...base, planFile: o["--plan"], authorizationFile: o["--authorization"], privateKeyFile: o["--private-key"], outDir: o["--out-dir"], send: !!o["--send"] });
|
|
154
|
+
else if (operation === "lifecycle") result = d.createDeploymentLifecycle({ ...base, executionFile: o["--execution"], executorPublicKeyFile: o["--executor-public-key"], project: o["--project"], sequence: Number(o["--sequence"]), pipelineId: o["--pipeline-id"], jobId: o["--job-id"], pipelineUrl: o["--pipeline-url"], reportUrl: o["--report-url"], outDir: o["--out-dir"] });
|
|
155
|
+
else throw new Error("deployment 子命令 plan/queue/run-authorized/run/deliver/lifecycle");
|
|
156
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n"); if (result.exitCode) process.exitCode = result.exitCode;
|
|
157
|
+
} else if (command === "attest-collected") {
|
|
158
|
+
const o = options(["--config", "--source", "--sha", "--env", "--manifest", "--private-key", "--issuer", "--out", "--expect-policy-hash", "--expect-rules-hash", "--expect-baseline-hash", "--expect-waivers-hash"]);
|
|
159
|
+
if (o.positional.length) throw new Error("attest-collected 不接受位置参数");
|
|
160
|
+
const { signCollectedReleaseProof } = await import("../lib/lifecycle-source.js");
|
|
161
|
+
protectOutput(o["--out"], [o["--config"], o["--source"], o["--private-key"]]);
|
|
162
|
+
const result = signCollectedReleaseProof({ configFile: o["--config"], sourceFile: o["--source"], sha: o["--sha"], env: o["--env"], manifestPath: o["--manifest"], privateKeyFile: o["--private-key"], issuer: o["--issuer"], outFile: o["--out"], expectPolicyHash: o["--expect-policy-hash"], expectRulesHash: o["--expect-rules-hash"], expectBaselineHash: o["--expect-baseline-hash"], expectWaiversHash: o["--expect-waivers-hash"] });
|
|
163
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
164
|
+
} else if (command === "collect-ci") {
|
|
165
|
+
const o = options(["--config", "--request", "--out"]);
|
|
166
|
+
if (o.positional.length || !o["--config"] || !o["--request"] || !o["--out"]) throw new Error("collect-ci 要求 --config --request --out 新证据目录");
|
|
167
|
+
const { collectCiSource } = await import("../lib/ci-source.js");
|
|
168
|
+
const result = await collectCiSource({ configFile: o["--config"], requestFile: o["--request"], outDir: o["--out"] });
|
|
169
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
170
|
+
process.exitCode = result.passed ? 0 : 2;
|
|
171
|
+
} else if (command === "lifecycle-build" || command === "lifecycle-review") {
|
|
172
|
+
const allowed = ["--config", "--source", "--sha", "--env", "--out", "--manifest", "--record", "--evidence-root", "--public-key", "--authorization-public-key", "--expect-authorization-issuer", "--report-url", "--sequence", "--profile", "--expect-review-policy-hash", "--expect-policy-hash", "--expect-rules-hash", "--expect-baseline-hash", "--expect-waivers-hash"];
|
|
173
|
+
const o = options(allowed);
|
|
174
|
+
if (o.positional.length || !o["--config"] || !o["--source"] || !o["--sha"] || !o["--out"]) throw new Error("生命周期构造要求 --config --source --sha --out 新目录");
|
|
175
|
+
const { createBuildLifecycle, createReviewLifecycle } = await import("../lib/lifecycle-source.js");
|
|
176
|
+
const base = { configFile: o["--config"], sourceFile: o["--source"], sha: o["--sha"], env: o["--env"], outDir: o["--out"] };
|
|
177
|
+
const result = command === "lifecycle-build" ? createBuildLifecycle({ ...base, manifestPath: o["--manifest"] }) : createReviewLifecycle({ ...base,
|
|
178
|
+
recordFile: o["--record"], evidenceRoot: o["--evidence-root"], publicKeyFile: o["--public-key"], authorizationPublicKeyFile: o["--authorization-public-key"], expectAuthorizationIssuer: o["--expect-authorization-issuer"],
|
|
179
|
+
reportUrl: o["--report-url"], sequence: Number(o["--sequence"]), profile: o["--profile"], expectReviewPolicyHash: o["--expect-review-policy-hash"], expectPolicyHash: o["--expect-policy-hash"], expectRulesHash: o["--expect-rules-hash"], expectBaselineHash: o["--expect-baseline-hash"], expectWaiversHash: o["--expect-waivers-hash"] });
|
|
180
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
181
|
+
} else if (command === "governance") {
|
|
182
|
+
const operation = rest.shift();
|
|
183
|
+
const allowed = {
|
|
184
|
+
receipt: ["--input", "--private-key", "--issuer", "--out"],
|
|
185
|
+
ingest: ["--config", "--state", "--event", "--summary", "--out"],
|
|
186
|
+
lifecycle: ["--config", "--state", "--event", "--source", "--out"],
|
|
187
|
+
action: ["--config", "--state", "--action", "--out"],
|
|
188
|
+
reconcile: ["--config", "--state", "--expectations", "--out"],
|
|
189
|
+
outbox: ["--config", "--state", "--include-digest", "--out"],
|
|
190
|
+
dispatch: ["--config", "--state", "--include-digest", "--send", "--out"],
|
|
191
|
+
migrate: ["--config", "--new-config", "--state", "--authorization", "--out"],
|
|
192
|
+
};
|
|
193
|
+
if (!Object.hasOwn(allowed, operation)) throw new Error("governance 子命令: receipt/ingest/lifecycle/action/reconcile/outbox/dispatch");
|
|
194
|
+
const o = options(allowed[operation]); if (o.positional.length) throw new Error("governance 不接受多余位置参数");
|
|
195
|
+
const g = await import("../lib/governance.js");
|
|
196
|
+
const required = operation === "receipt" ? ["--input", "--private-key", "--issuer", "--out"] : ["--config", "--state", ...(operation === "ingest" ? ["--event", "--summary"] : operation === "lifecycle" ? ["--event", "--source"] : operation === "action" ? ["--action"] : operation === "reconcile" ? ["--expectations"] : operation === "migrate" ? ["--new-config", "--authorization"] : [])];
|
|
197
|
+
for (const key of required) if (!o[key]) throw new Error(`缺少 ${key}`);
|
|
198
|
+
protectOutput(o["--out"], [o["--state"], o["--config"], o["--input"], o["--event"], o["--summary"], o["--source"], o["--action"], o["--expectations"], o["--private-key"]]);
|
|
199
|
+
if (operation !== "receipt") protectOutput(o["--out"], [g.loadGovernanceConfig(o["--config"]).publicKeyFile]);
|
|
200
|
+
let result;
|
|
201
|
+
const base = { configFile: o["--config"], stateFile: o["--state"], includeDigest: !!o["--include-digest"] };
|
|
202
|
+
if (operation === "receipt") { const { readFileSync } = await import("node:fs"); result = g.signPlatformReceipt(JSON.parse(readFileSync(o["--input"], "utf8")), { privateKeyFile: o["--private-key"], issuer: o["--issuer"] }); }
|
|
203
|
+
else if (operation === "ingest") result = g.ingestGovernance({ ...base, eventFile: o["--event"], summaryFile: o["--summary"] });
|
|
204
|
+
else if (operation === "lifecycle") result = g.ingestLifecycleGovernance({ ...base, eventFile: o["--event"], sourceFile: o["--source"] });
|
|
205
|
+
else if (operation === "action") result = g.actionGovernance({ ...base, actionFile: o["--action"] });
|
|
206
|
+
else if (operation === "reconcile") result = g.reconcileGovernance({ ...base, expectationsFile: o["--expectations"] });
|
|
207
|
+
else if (operation === "outbox") result = g.outboxGovernance(base);
|
|
208
|
+
else if (operation === "migrate") result = g.migrateGovernanceConfig({ ...base, newConfigFile: o["--new-config"], authorizationFile: o["--authorization"] });
|
|
209
|
+
else result = await g.dispatchGovernance({ ...base, send: !!o["--send"] });
|
|
210
|
+
if (o["--out"]) writeJson(o["--out"], result); else process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
211
|
+
if (result.results?.some((x) => x.status !== "delivered") || result.unknownDeliveries?.length || result.deadLetters?.length) process.exitCode = 2;
|
|
54
212
|
} else if (command === "cost") {
|
|
55
213
|
const o = options(["--usage", "--out"]);
|
|
56
214
|
if (!o.positional[0] || !o["--out"]) throw new Error("cost 必须提供工件目录和 --out;不默认将完整统计塞入控制台");
|
|
@@ -93,10 +251,24 @@ try {
|
|
|
93
251
|
writeJson(o["--out"], signGateProof({ ...proofOptions(o), summaryFile: o["--summary"] || o.positional[0],
|
|
94
252
|
profile: o["--profile"], privateKeyFile: o["--private-key"], issuer: o["--issuer"],
|
|
95
253
|
pipelineId: o["--pipeline-id"], jobId: o["--job-id"], promotionRecordFile: o["--promotion-record"] }));
|
|
254
|
+
} else if (command === "review-draft") {
|
|
255
|
+
const o = options(["--input", "--evidence-root", "--out"]);
|
|
256
|
+
if (o.positional.length || !o["--input"] || !o["--out"]) throw new Error("review-draft 要求 --input --out,证据须放在 --evidence-root 内");
|
|
257
|
+
const { createReviewDraft } = await import("../lib/review.js");
|
|
258
|
+
const result = createReviewDraft({ inputFile: o["--input"], evidenceRoot: o["--evidence-root"], outDir: o["--out"] });
|
|
259
|
+
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
96
260
|
} else if (command === "review-sign") {
|
|
97
|
-
const o = options(["--private-key", "--reviewer-id", "--author-id", "--project", "--sha", "--out"]);
|
|
98
|
-
|
|
99
|
-
|
|
261
|
+
const o = options(["--private-key", "--reviewer-id", "--author-id", "--project", "--sha", "--out", "--authorization", "--authorization-public-key", "--expect-authorization-issuer", "--evidence-root", "--expect-review-policy-hash", "--profile", "--env", "--expect-policy-hash", "--expect-rules-hash", "--expect-baseline-hash", "--expect-waivers-hash"]);
|
|
262
|
+
const recordFile = o.positional[0];
|
|
263
|
+
protectOutput(o["--out"], [recordFile, o["--private-key"], o["--authorization"]]);
|
|
264
|
+
const { validateReviewOutputLocation } = await import("../lib/review.js");
|
|
265
|
+
const destination = validateReviewOutputLocation({ outFile: o["--out"], recordFile, evidenceRoot: o["--evidence-root"] });
|
|
266
|
+
const signedReview = signReviewRecord({ recordFile, privateKeyFile: o["--private-key"],
|
|
267
|
+
reviewerId: o["--reviewer-id"], authorId: o["--author-id"], project: o["--project"], sha: o["--sha"],
|
|
268
|
+
authorizationFile: o["--authorization"], authorizationPublicKeyFile: o["--authorization-public-key"], expectAuthorizationIssuer: o["--expect-authorization-issuer"], evidenceRoot: o["--evidence-root"], expectReviewPolicyHash: o["--expect-review-policy-hash"],
|
|
269
|
+
profile: o["--profile"], env: o["--env"], expectPolicyHash: o["--expect-policy-hash"], expectRulesHash: o["--expect-rules-hash"], expectBaselineHash: o["--expect-baseline-hash"], expectWaiversHash: o["--expect-waivers-hash"] });
|
|
270
|
+
writeFileSync(destination, JSON.stringify(signedReview, null, 2) + "\n", { flag: "wx", mode: 0o600 });
|
|
271
|
+
console.log(`[review-sign] 已写入 ${destination}`);
|
|
100
272
|
} else if (command === "verify-artifact") {
|
|
101
273
|
const r = verifyArtifact(proofOptions(options(PROOF_FLAGS)));
|
|
102
274
|
if (!r.ok) throw new Error(r.errors.join("; "));
|
|
@@ -111,9 +283,9 @@ try {
|
|
|
111
283
|
for (const reason of r.reasons) console.error(reason);
|
|
112
284
|
process.exitCode = r.exitCode;
|
|
113
285
|
} else if (command === "promote-apply") {
|
|
114
|
-
const o = options([...PROOF_FLAGS, "--record", "--remote-url", "--bundle", "--review", "--review-public-key", "--out"]);
|
|
286
|
+
const o = options([...PROOF_FLAGS, "--record", "--remote-url", "--bundle", "--review", "--review-public-key", "--review-evidence-root", "--expect-review-policy-hash", "--authorization-public-key", "--expect-authorization-issuer", "--out"]);
|
|
115
287
|
const r = applyPromotion({ ...proofOptions(o), recordFile: o["--record"], remoteUrl: o["--remote-url"],
|
|
116
|
-
bundleFile: o["--bundle"], reviewFile: o["--review"], reviewPublicKeyFile: o["--review-public-key"], outDir: o["--out"] });
|
|
288
|
+
bundleFile: o["--bundle"], reviewFile: o["--review"], reviewPublicKeyFile: o["--review-public-key"], reviewEvidenceRoot: o["--review-evidence-root"], expectReviewPolicyHash: o["--expect-review-policy-hash"], authorizationPublicKeyFile: o["--authorization-public-key"], expectAuthorizationIssuer: o["--expect-authorization-issuer"], outDir: o["--out"] });
|
|
117
289
|
console.log(`[promote-apply] ${r.status}`);
|
|
118
290
|
for (const reason of r.reasons) console.error(reason);
|
|
119
291
|
process.exitCode = r.exitCode;
|
|
@@ -121,5 +293,5 @@ try {
|
|
|
121
293
|
if (rest.length) throw new Error("self-test 不接受额外参数");
|
|
122
294
|
const { runAllFixtures } = await import("../scripts/run-fixtures.mjs");
|
|
123
295
|
process.exitCode = await runAllFixtures();
|
|
124
|
-
} else throw new Error("用法: wl-skills-gate <run|inspect|cost|fix|validate-report|commit-message|manifest|attest|review-sign|verify-artifact|promote|promote-apply|self-test>,详见 docs/README.md");
|
|
296
|
+
} else throw new Error("用法: wl-skills-gate <onboard|run|doctor|automation|control|collect-ci|review-facts|review-ci|review-collect|review-publish|lifecycle-build|lifecycle-review|governance|inspect|cost|fix|validate-report|commit-message|manifest|attest|attest-collected|release-set|deployment|review-draft|review-sign|verify-artifact|promote|promote-apply|self-test>,详见 docs/README.md");
|
|
125
297
|
} catch (e) { console.error(`[${command || "wl-skills-gate"}] ${e.message}`); process.exitCode = 2; }
|
package/docs/01-quick-start.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 01 快速开始
|
|
2
2
|
|
|
3
|
-
对应 3.1/4.1、A1/A3。需要 Node ≥
|
|
3
|
+
对应 3.1/4.1、A1/A3。需要 Node ≥22.12,业务检查器与项目依赖需另行准备。
|
|
4
4
|
|
|
5
5
|
## 包仓库自测
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ node bin/wl-skills-gate.js self-test
|
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
# 取得书面授权后,从公共 npm registry 安装固定版本。
|
|
20
|
-
pnpm add -D --save-exact @agile-team/wl-skills-gate@0.
|
|
20
|
+
pnpm add -D --save-exact @agile-team/wl-skills-gate@0.7.0
|
|
21
21
|
mkdir -p quality
|
|
22
22
|
# 从安装包 templates/quality 取模板,按真实检查器和工具版本修改。
|
|
23
23
|
pnpm exec wl-skills-gate run --profile standard
|
package/docs/02-config.md
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
对应 3.3/3.4/3.6、A1。项目 quality/ 支持 policy.yml/.yaml/.json、waivers.yml/.yaml/.json、baseline.json、rules.lock.json。
|
|
4
4
|
|
|
5
|
-
0.
|
|
5
|
+
0.7.0 源码修订(实际 registry 发布另验):`cmd-json.format` 可选 wl-kit/wl-ui/wl-bd,`captureStdout: true` 必须同时声明 file;`java-xml` 必填 format=checkstyle/pmd/p3c/spotbugs 与 file。java-xml 与 junit 可声明共享 producer,同组必须有相同 tool/command/timeoutMs,在本轮只生产一次;不允许将两个适配器混为同一组。见 [Java 静态片段](../templates/quality/java-static-checks.yml)、[适配器契约](05-adapters.md)与 [14 执行约束](14-low-token-execution.md)。
|
|
6
|
+
|
|
7
|
+
JUnit 单报告保留 file;多报告使用与 file 互斥的 files 明确路径数组,并必填 reportDirs(各报告直接父目录的完整集合)。requiredSuites 精确匹配 testsuite.name,requiredTests 使用 classname#name;目录全部 XML 必须与 files 一致,不使用 glob 或动态“实际清单自动批准”。全过程及签发核验真实 testcase/计数/必测、原始摘要、SHA/eventId/sourceDigest;终轮报告被改也 invalid。示例与 Java 单元计划见 [16 正式操作入口](16-project-ci-integration.md)。
|
|
8
|
+
|
|
9
|
+
仅 java-xml 允许 `sourceRoots`,须为无重复、实际存在且没有符号链接的项目内相对目录数组;SpotBugs 未配置时只兼容 `src/main/java`,不搜索整个仓库。详见 [Java 分级与定位](15-java-report-triage.md)。风险分级和测试拆分见 [13 质量成本与隔离](13-quality-cost-and-isolation.md)。`enforceWarnings: false` 只控制 Gate 警告,不改变原生 Maven 插件的失败行为。
|
|
6
10
|
|
|
7
11
|
policy 必需。没有 baseline/waivers 表示没有登记任何基线/例外,摘要为 `sha256("absent")`;存在的文件损坏时失败关闭。受控 `--sha`、release 和正式签发时,有文件就必须提供批准的 `--expect-baseline-hash` / `--expect-waivers-hash`,空文件也一样;本地非受控诊断可不传。
|
|
8
12
|
|
|
@@ -39,7 +43,7 @@ rules.lock.json 示例:
|
|
|
39
43
|
```json
|
|
40
44
|
{
|
|
41
45
|
"lockVersion": 1,
|
|
42
|
-
"wl-skills-gate": "0.
|
|
46
|
+
"wl-skills-gate": "0.7.0",
|
|
43
47
|
"tools": {
|
|
44
48
|
"TS-TYPECHECK": "<实际版本命令完整输出>",
|
|
45
49
|
"FE-ESLINT": "<实际版本命令完整输出>"
|
|
@@ -75,7 +79,7 @@ tools 以 check id 为键。执行 versionCommand 时使用其真实输出,随
|
|
|
75
79
|
|
|
76
80
|
## 配置格式与修复白名单
|
|
77
81
|
|
|
78
|
-
yaml-lite
|
|
82
|
+
yaml-lite 支持简单键值、一级列表、流式数组、布尔/null、裸十进制安全整数、引号与注释;timeoutMs 等整数可直接写 600000。引号数字仍是字符串,日期/普通参数不转数值,超出安全整数范围拒绝。检查内 files/reportDirs 等用行内数组;复杂或嵌套 fixer 结构用 policy.json,见 04。重复键和不支持语法失败关闭。未使用的工具包不强制安装或登记。
|
|
79
83
|
|
|
80
84
|
受控 --sha / release 的全部必需检查还须实际查询工具版本并匹配 rules.lock.tools;仅 JSON 自报版本不能签发正式证明。ESLint/typecheck 可查询对应 bin --version,其他 adapter 需登记受控 versionCommand。
|
|
81
85
|
|
package/docs/05-adapters.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
| typecheck | 实际 vue-tsc/tsc;缺失/超时 invalid,类型失败不可基线化/豁免;版本命令与 bin 对应 |
|
|
9
9
|
| cmd-json | 统一 findings,或 format=wl-kit/wl-ui/wl-bd 原生完整报告;captureStdout+file 支持大 JSON 文件描述符接收;默认 exit=0,显式接受 1 必须有问题证据 |
|
|
10
10
|
| raw-json | 本地 fixture/报告调试可读文件;受控 --sha/release 必须配置本次 command 产生新文件 |
|
|
11
|
-
| junit | 无 DTD
|
|
11
|
+
| junit | 无 DTD 的真实完整 XML;file 单份或 files+reportDirs 全集;requiredSuites/requiredTests 核验套件和用例;计数/testcase 一致,零用例/跳过/失败阻断;支持同轮共享 producer |
|
|
12
12
|
| sarif | SARIF 2.1.0,runs/results 完整、工具执行成功;默认风险依据 rule 配置或 warning,不静默降 info |
|
|
13
13
|
| java-xml | format=checkstyle/pmd/p3c/spotbugs;解析原 XML、保留原生身份;Gate单源表分级,底线error、上下文复核warning;sourceRoots精确映射多模块main/test;生产命令须exit0,分析错误/缺类/零类/坏报告/定位失效invalid;可显式同producer共用一次本轮生产 |
|
|
14
14
|
|
|
@@ -22,12 +22,22 @@ Java context 是稳定 JSON 字符串,含 producer、真实报告引擎和自
|
|
|
22
22
|
|
|
23
23
|
## 新鲜度与失败关闭
|
|
24
24
|
|
|
25
|
-
受控检查的文件报告必须由 adapter 的 command
|
|
25
|
+
受控检查的文件报告必须由 adapter 的 command 在本次生成;清理前先预检全部声明范围,禁止把已跟踪源码/本轮源码快照或不安全路径当输出删除。cmd-json 默认不把 exit 1 当成功;确实表示发现问题时在批准策略登记 okExitCodes=[0,1],报告必须反映问题。声明成功但没有有效测试、异常退出却空报告、缺文件、损坏、超时均拒绝。
|
|
26
26
|
|
|
27
27
|
报告生产命令收到 WL_GATE_EVENT_ID、WL_GATE_COMMIT_SHA,可写入自己的来源字段。可信来源还依赖受控执行器与独立平台查询;JSON 中的 toolVersion、passed、completed 字样不能独自证明执行发生。
|
|
28
28
|
|
|
29
29
|
所有档位都检测执行前后源码/HEAD 变化;检查中修改源码返回 invalid。报告和构建输出应放在声明的生成目录,检查命令不能带 --fix。
|
|
30
30
|
|
|
31
|
+
## JUnit 全集与同轮生产(0.7.0)
|
|
32
|
+
|
|
33
|
+
file 与 files 互斥;使用 files 时必填 reportDirs,精确等于每份报告直接父目录的集合。生产前清理这些目录中旧 XML;新一轮目录里的全部 XML 必须与 files 全集完全相同。缺/未登记报告、子目录、symlink、路径别名、glob、坏 UTF-8/结构/计数和跨报告重复 classname#name 返回 invalid。参数化用例须保留完整不同名称;不能手写汇总计数替代 XML 中 testcase。
|
|
34
|
+
|
|
35
|
+
requiredSuites 精确 testsuite.name;requiredTests 为 classname#name,必须真实成功。每份报告/套件的零用例、skipped、failure/error 均形成不可基线化阻断。生产命令 exit 1 只有存在真实 failure/error 时才可消费;仅 skipped/缺必测不能解释异常退出。更高退出码、超时或缺新报告为 invalid。
|
|
36
|
+
|
|
37
|
+
JUnit producer 与 java-xml producer 分组独立,同组 tool/command/timeoutMs 一致,一轮执行一次。每份原始字节只读解析并核验 SHA-256,绑定 eventId/commitSha/sourceDigest;消费后到终轮的覆盖/删除/修改也拒绝。签发/部署/治理摄入对完整通过证据独立复核,不只相信 passed 字段。跨作业复制文件不能充当本轮生产。
|
|
38
|
+
|
|
39
|
+
[Java 单元生产器](../templates/scripts-quality/java-unit.mjs)和[批准 plan](../templates/quality/java-unit.plan.json)负责依赖准备及真实模块单元执行。它对任何 Maven 非零保守返回 2/invalid,保留原始阶段日志;JUnit 适配器自身能识别符合契约的真实失败为 blocked,两者不能混为一种退出口径。
|
|
40
|
+
|
|
31
41
|
## Kit/UI/BD/Test 接入
|
|
32
42
|
|
|
33
43
|
优先调用其确定性只读 CLI,将真实 findings 转入统一契约。现有 AI Skill 不一定具备确定性 CLI;没有 CLI/JSON 输出的能力需实现适配,涉及业务判断的能力保留人工 Review,不写成自动化已完成。
|